diff options
Diffstat (limited to 'chromium/third_party/skia/experimental/PdfViewer/SkPdfFont.h')
-rw-r--r-- | chromium/third_party/skia/experimental/PdfViewer/SkPdfFont.h | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/chromium/third_party/skia/experimental/PdfViewer/SkPdfFont.h b/chromium/third_party/skia/experimental/PdfViewer/SkPdfFont.h new file mode 100644 index 00000000000..cc490553d1a --- /dev/null +++ b/chromium/third_party/skia/experimental/PdfViewer/SkPdfFont.h @@ -0,0 +1,479 @@ +/* + * 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 |