| /* |
| * 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 |