/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
// TODO(edisonn): this file not commented much on purpose.
// It will probably need heavy refactoring soon anyway to support all encodings, fonts and
// proper text sizing and spacing
#ifndef SkPdfFont_DEFINED
#define SkPdfFont_DEFINED
#include "SkPdfContext.h"
#include "SkPdfHeaders_autogen.h"
#include "SkPdfMapper_autogen.h"
#include "SkPdfUtils.h"
#include "SkTypeface.h"
#include "SkTDict.h"
#include "SkUtils.h"
class SkPdfType0Font;
class SkPdfType1Font;
class SkPdfType3Font;
class SkPdfTrueTypeFont;
class SkPdfMultiMasterFont;
class SkPdfFont;
struct SkPdfStandardFontEntry {
// We don't own this pointer!
const char* fName;
bool fIsBold;
bool fIsItalic;
SkPdfStandardFontEntry()
: fName(NULL),
fIsBold(false),
fIsItalic(false) {}
SkPdfStandardFontEntry(const char* name, bool bold, bool italic)
: fName(name),
fIsBold(bold),
fIsItalic(italic) {}
};
SkTDict<SkPdfStandardFontEntry>& getStandardFonts();
SkTypeface* SkTypefaceFromPdfStandardFont(const char* fontName, bool bold, bool italic);
SkPdfFont* fontFromName(SkPdfNativeDoc* doc, SkPdfNativeObject* obj, const char* fontName);
struct SkUnencodedText {
void* text;
int len;
public:
SkUnencodedText(const SkPdfString* obj) {
text = (void*)obj->c_str();
len = (int) obj->lenstr();
}
};
struct SkDecodedText {
uint16_t* text;
int len;
public:
unsigned int operator[](int i) const { return text[i]; }
int size() const { return len; }
};
struct SkUnicodeText {
uint16_t* text;
int len;
public:
unsigned int operator[](int i) const { return text[i]; }
int size() const { return len; }
};
class SkPdfEncoding {
public:
virtual ~SkPdfEncoding() {}
virtual bool decodeText(const SkUnencodedText& textIn, SkDecodedText* textOut) const = 0;
static SkPdfEncoding* fromName(const char* name);
};
SkTDict<SkPdfEncoding*>& getStandardEncodings();
class SkPdfToUnicode {
// TODO(edisonn): hide public members
public:
unsigned short* fCMapEncoding;
unsigned char* fCMapEncodingFlag;
SkPdfToUnicode(SkPdfNativeDoc* parsed, SkPdfStream* stream);
};
class SkPdfIdentityHEncoding : public SkPdfEncoding {
public:
virtual ~SkPdfIdentityHEncoding() {}
virtual bool decodeText(const SkUnencodedText& textIn, SkDecodedText* textOut) const {
// TODO(edisonn): SkASSERT(textIn.len % 2 == 0); or report error?
uint16_t* text = (uint16_t*)textIn.text;
textOut->text = new uint16_t[textIn.len / 2];
textOut->len = textIn.len / 2;
for (int i = 0; i < textOut->len; i++) {
textOut->text[i] = ((text[i] << 8) & 0xff00) | ((text[i] >> 8) & 0x00ff);
}
return true;
}
static SkPdfIdentityHEncoding* instance() {
static SkPdfIdentityHEncoding* inst = new SkPdfIdentityHEncoding();
return inst;
}
};
// TODO(edisonn): using this one when no encoding is specified
class SkPdfDefaultEncoding : public SkPdfEncoding {
public:
virtual ~SkPdfDefaultEncoding() {}
virtual bool decodeText(const SkUnencodedText& textIn, SkDecodedText* textOut) const {
// TODO(edisonn): SkASSERT(textIn.len % 2 == 0); or report error?
unsigned char* text = (unsigned char*)textIn.text;
textOut->text = new uint16_t[textIn.len];
textOut->len = textIn.len;
for (int i = 0; i < textOut->len; i++) {
textOut->text[i] = text[i];
}
return true;
}
static SkPdfDefaultEncoding* instance() {
static SkPdfDefaultEncoding* inst = new SkPdfDefaultEncoding();
return inst;
}
};
class SkPdfCIDToGIDMapIdentityEncoding : public SkPdfEncoding {
public:
virtual ~SkPdfCIDToGIDMapIdentityEncoding() {}
virtual bool decodeText(const SkUnencodedText& textIn, SkDecodedText* textOut) const {
// TODO(edisonn): SkASSERT(textIn.len % 2 == 0); or report error?
uint16_t* text = (uint16_t*)textIn.text;
textOut->text = new uint16_t[textIn.len / 2];
textOut->len = textIn.len / 2;
for (int i = 0; i < textOut->len; i++) {
textOut->text[i] = ((text[i] << 8) & 0xff00) | ((text[i] >> 8) & 0x00ff);
}
return true;
}
static SkPdfCIDToGIDMapIdentityEncoding* instance() {
static SkPdfCIDToGIDMapIdentityEncoding* inst = new SkPdfCIDToGIDMapIdentityEncoding();
return inst;
}
};
class SkPdfFont {
public:
SkPdfFont* fBaseFont;
SkPdfEncoding* fEncoding;
SkPdfToUnicode* fToUnicode;
public:
SkPdfFont() : fBaseFont(NULL), fEncoding(SkPdfDefaultEncoding::instance()), fToUnicode(NULL) {}
virtual ~SkPdfFont() {
// TODO(edisonn): NYI (will leak for now)
}
const SkPdfEncoding* encoding() const {return fEncoding;}
void drawText(const SkDecodedText& text, SkPaint* paint, SkPdfContext* pdfContext,
SkCanvas* canvas) {
for (int i = 0 ; i < text.size(); i++) {
canvas->setMatrix(pdfContext->fGraphicsState.fMatrixTm);
#ifdef PDF_TRACE
SkPoint point = SkPoint::Make(SkDoubleToScalar(0), SkDoubleToScalar(0));
pdfContext->fGraphicsState.fMatrixTm.mapPoints(&point, 1);
printf("DrawText at (%f, %f)\n", SkScalarToDouble(point.x()),
SkScalarToDouble(point.y()));
#endif // PDF_TRACE
#ifdef PDF_TRACE_DRAWTEXT
SkPaint col;
col.setColor(SK_ColorMAGENTA);
SkRect rect = SkRect::MakeXYWH(SkDoubleToScalar(0.0),
SkDoubleToScalar(0.0),
SkDoubleToScalar(10.0),
SkDoubleToScalar(10.0));
canvas->save();
canvas->setMatrix(pdfContext->fGraphicsState.fMatrixTm);
canvas->drawRect(rect, col);
canvas->restore();
#endif
double width = drawOneChar(text[i], paint, pdfContext, canvas);
pdfContext->fGraphicsState.fMatrixTm.preTranslate(SkDoubleToScalar(width),
SkDoubleToScalar(0.0));
}
}
void ToUnicode(const SkDecodedText& textIn, SkUnicodeText* textOut) const {
if (fToUnicode) {
textOut->text = new uint16_t[textIn.len];
textOut->len = textIn.len;
for (int i = 0; i < textIn.len; i++) {
textOut->text[i] = fToUnicode->fCMapEncoding[textIn.text[i]];
}
} else {
textOut->text = textIn.text;
textOut->len = textIn.len;
}
};
inline unsigned int ToUnicode(unsigned int ch) const {
if (fToUnicode && fToUnicode->fCMapEncoding) {
return fToUnicode->fCMapEncoding[ch];
} else {
return ch;
}
};
static SkPdfFont* fontFromPdfDictionary(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict);
static SkPdfFont* Default() {return fontFromName(NULL, NULL, "TimesNewRoman");}
static SkPdfType0Font* fontFromType0FontDictionary(SkPdfNativeDoc* doc,
SkPdfType0FontDictionary* dict);
static SkPdfType1Font* fontFromType1FontDictionary(SkPdfNativeDoc* doc,
SkPdfType1FontDictionary* dict);
static SkPdfType3Font* fontFromType3FontDictionary(SkPdfNativeDoc* doc,
SkPdfType3FontDictionary* dict);
static SkPdfTrueTypeFont* fontFromTrueTypeFontDictionary(SkPdfNativeDoc* doc,
SkPdfTrueTypeFontDictionary* dict);
static SkPdfMultiMasterFont* fontFromMultiMasterFontDictionary(
SkPdfNativeDoc* doc, SkPdfMultiMasterFontDictionary* dict);
static SkPdfFont* fontFromFontDescriptor(SkPdfNativeDoc* doc,
SkPdfFontDescriptorDictionary* fd,
bool loadFromName = true);
public:
virtual double drawOneChar(unsigned int ch, SkPaint* paint, SkPdfContext* pdfContext,
SkCanvas* canvas) = 0;
virtual void afterWord(SkPaint* paint, SkMatrix* matrix) = 0;
private:
static SkPdfFont* fontFromPdfDictionaryOnce(SkPdfNativeDoc* doc, SkPdfFontDictionary* dict);
};
class SkPdfStandardFont : public SkPdfFont {
SkTypeface* fTypeface;
public:
SkPdfStandardFont(SkTypeface* typeface) : fTypeface(typeface) {}
public:
virtual double drawOneChar(unsigned int ch, SkPaint* paint, SkPdfContext* pdfContext,
SkCanvas* canvas) {
paint->setTypeface(fTypeface);
paint->setTextEncoding(SkPaint::kUTF8_TextEncoding);
unsigned long ch4 = ch;
char utf8[10];
size_t len = SkUTF8_FromUnichar((SkUnichar) ch4, utf8);
canvas->drawText(utf8, len, SkDoubleToScalar(0), SkDoubleToScalar(0), *paint);
SkScalar textWidth = paint->measureText(utf8, len);
return SkScalarToDouble(textWidth);
}
virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {}
};
class SkPdfType0Font : public SkPdfFont {
public:
SkPdfType0Font(SkPdfNativeDoc* doc, SkPdfType0FontDictionary* dict);
public:
virtual double drawOneChar(unsigned int ch, SkPaint* paint, SkPdfContext* pdfContext,
SkCanvas* canvas) {
return fBaseFont->drawOneChar(ToUnicode(ch), paint, pdfContext, canvas);
}
virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {
}
};
class SkPdfType1Font : public SkPdfFont {
public:
SkPdfType1Font(SkPdfNativeDoc* doc, SkPdfType1FontDictionary* dict) {
if (dict->has_FontDescriptor()) {
fBaseFont = SkPdfFont::fontFromFontDescriptor(doc, dict->FontDescriptor(doc));
} else {
fBaseFont = fontFromName(doc, dict, dict->BaseFont(doc).c_str());
}
if (dict->isEncodingAName(doc)) {
fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName(doc).c_str());
} else if (dict->isEncodingADictionary(doc)) {
//SkPdfDictionary* dictEnc = dict->getEncodingAsDictionary(doc);
}
dict->FontDescriptor(doc);
}
public:
virtual double drawOneChar(unsigned int ch, SkPaint* paint, SkPdfContext* pdfContext,
SkCanvas* canvas) {
return fBaseFont->drawOneChar(ToUnicode(ch), paint, pdfContext, canvas);
}
virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {
}
};
class SkPdfTrueTypeFont : public SkPdfType1Font {
public:
SkPdfTrueTypeFont(SkPdfNativeDoc* doc, SkPdfTrueTypeFontDictionary* dict)
: SkPdfType1Font(doc, dict) {}
};
class SkPdfMultiMasterFont : public SkPdfType1Font {
public:
SkPdfMultiMasterFont(SkPdfNativeDoc* doc, SkPdfMultiMasterFontDictionary* dict)
: SkPdfType1Font(doc, dict) {}
};
/*
class CIDToGIDMap {
virtual unsigned int map(unsigned int cid) = 0;
static CIDToGIDMap* fromName(const char* name);
};
class CIDToGIDMap_Identity {
virtual unsigned int map(unsigned int cid) { return cid; }
static CIDToGIDMap_Identity* instance() {
static CIDToGIDMap_Identity* inst = new CIDToGIDMap_Identity();
return inst;
}
};
CIDToGIDMap* CIDToGIDMap::fromName(const char* name) {
// The only one supported right now is Identity
if (strcmp(name, "Identity") == 0) {
return CIDToGIDMap_Identity::instance();
}
#ifdef PDF_TRACE
// TODO(edisonn): warning/report
printf("Unknown CIDToGIDMap: %s\n", name);
#endif
return NULL;
}
CIDToGIDMap* fCidToGid;
*/
class SkPdfType3Font : public SkPdfFont {
struct Type3FontChar {
SkPdfNativeObject* fObj;
double fWidth;
};
SkPdfDictionary* fCharProcs;
SkPdfEncodingDictionary* fEncodingDict;
unsigned int fFirstChar;
unsigned int fLastChar;
SkRect fFontBBox;
SkMatrix fFonMatrix;
Type3FontChar* fChars;
public:
SkPdfType3Font(SkPdfNativeDoc* parsed, SkPdfType3FontDictionary* dict) {
fBaseFont = fontFromName(parsed, dict, dict->BaseFont(parsed).c_str());
if (dict->has_Encoding()) {
if (dict->isEncodingAName(parsed)) {
fEncoding = SkPdfEncoding::fromName(dict->getEncodingAsName(parsed).c_str());
} else if (dict->isEncodingAEncodingdictionary(parsed)) {
// No encoding.
fEncoding = SkPdfDefaultEncoding::instance();
fEncodingDict = dict->getEncodingAsEncodingdictionary(parsed);
}
}
// null?
fCharProcs = dict->CharProcs(parsed);
fToUnicode = NULL;
if (dict->has_ToUnicode()) {
fToUnicode = new SkPdfToUnicode(parsed, dict->ToUnicode(parsed));
}
fFirstChar = (unsigned int)dict->FirstChar(parsed);
fLastChar = (unsigned int)dict->LastChar(parsed);
fFonMatrix = dict->has_FontMatrix() ? dict->FontMatrix(parsed) : SkMatrix::I();
if (dict->has_FontBBox()) {
fFontBBox = dict->FontBBox(parsed);
}
fChars = new Type3FontChar[fLastChar - fFirstChar + 1];
memset(fChars, 0, sizeof(fChars[0]) * (fLastChar - fFirstChar + 1));
const SkPdfArray* widths = dict->Widths(parsed);
for (unsigned int i = 0 ; i < widths->size(); i++) {
if ((fFirstChar + i) >= fFirstChar && (fFirstChar + i) <= fLastChar) {
fChars[i].fWidth = (*widths)[i]->numberValue();
} else {
// TODO(edisonn): report pdf corruption
}
}
const SkPdfArray* diffs = fEncodingDict->Differences(parsed);
unsigned int j = fFirstChar;
for (unsigned int i = 0 ; i < diffs->size(); i++) {
if ((*diffs)[i]->isInteger()) {
j = (unsigned int)(*diffs)[i]->intValue();
} else if ((*diffs)[i]->isName()) {
if (j >= fFirstChar && j <= fLastChar) {
fChars[j - fFirstChar].fObj = fCharProcs->get((*diffs)[i]);
} else {
// TODO(edisonn): report pdf corruption
}
j++;
} else {
// TODO(edisonn): report bad pdf
}
}
}
public:
virtual double drawOneChar(unsigned int ch, SkPaint* paint, SkPdfContext* pdfContext,
SkCanvas* canvas) {
if (ch < fFirstChar || ch > fLastChar || !fChars[ch - fFirstChar].fObj) {
return fBaseFont->drawOneChar(ToUnicode(ch), paint, pdfContext, canvas);
}
#ifdef PDF_TRACE
printf("Type 3 char to unicode: %c\n", ToUnicode(ch));
if (ToUnicode(ch) == 'A') {
printf("break;\n");
}
#endif
// TODO(edisonn): is it better to resolve the reference at load time, or now?
doType3Char(pdfContext,
canvas,
pdfContext->fPdfDoc->resolveReference(fChars[ch - fFirstChar].fObj),
fFontBBox,
fFonMatrix,
pdfContext->fGraphicsState.fCurFontSize);
// TODO(edisonn): verify/test translate code, not tested yet
pdfContext->fGraphicsState.fMatrixTm.preTranslate(
SkDoubleToScalar(pdfContext->fGraphicsState.fCurFontSize *
fChars[ch - fFirstChar].fWidth),
SkDoubleToScalar(0.0));
return fChars[ch - fFirstChar].fWidth;
}
virtual void afterWord(SkPaint* paint, SkMatrix* matrix) {}
};
#endif // SkPdfFont_DEFINED