diff options
author | 2011-03-04 21:43:27 +0000 | |
---|---|---|
committer | 2011-03-04 21:43:27 +0000 | |
commit | 9db86bb9cd1b77be0afc504ccc07026e4282d7e7 (patch) | |
tree | ee61410f9edae69b38962e82cbbade4d8610e635 /src | |
parent | 5aaa69e4339e229adfb05e96084a8ec0a590238b (diff) |
PDF Type3 Support.
git-svn-id: http://skia.googlecode.com/svn/trunk@892 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/pdf/SkPDFDevice.cpp | 169 | ||||
-rw-r--r-- | src/pdf/SkPDFFont.cpp | 330 | ||||
-rw-r--r-- | src/pdf/pdf_files.mk | 3 | ||||
-rw-r--r-- | src/ports/SkFontHost_win.cpp | 17 |
4 files changed, 248 insertions, 271 deletions
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index ff9e4db433..62f4fa8424 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -26,20 +26,13 @@ #include "SkPDFFormXObject.h" #include "SkPDFTypes.h" #include "SkPDFStream.h" +#include "SkPDFUtils.h" #include "SkRect.h" #include "SkString.h" #include "SkTextFormatParams.h" #include "SkTypeface.h" #include "SkTypes.h" -#define NOT_IMPLEMENTED(condition, assert) \ - do { \ - if (condition) { \ - fprintf(stderr, "NOT_IMPLEMENTED: " #condition "\n"); \ - SkDEBUGCODE(SkASSERT(!assert);) \ - } \ - } while(0) - // Utility functions namespace { @@ -171,7 +164,7 @@ void SkPDFDevice::setMatrixClip(const SkMatrix& matrix, SkPath clipPath; if (region.getBoundaryPath(&clipPath)) { - emitPath(clipPath); + SkPDFUtils::EmitPath(clipPath, &fContent); SkPath::FillType clipFill = clipPath.getFillType(); NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, @@ -212,25 +205,28 @@ void SkPDFDevice::drawPoints(const SkDraw& d, SkCanvas::PointMode mode, switch (mode) { case SkCanvas::kPolygon_PointMode: updateGSFromPaint(paint, false); - moveTo(points[0].fX, points[0].fY); - for (size_t i = 1; i < count; i++) - appendLine(points[i].fX, points[i].fY); - strokePath(); + SkPDFUtils::MoveTo(points[0].fX, points[0].fY, &fContent); + for (size_t i = 1; i < count; i++) { + SkPDFUtils::AppendLine(points[i].fX, points[i].fY, &fContent); + } + SkPDFUtils::StrokePath(&fContent); break; case SkCanvas::kLines_PointMode: updateGSFromPaint(paint, false); for (size_t i = 0; i < count/2; i++) { - moveTo(points[i * 2].fX, points[i * 2].fY); - appendLine(points[i * 2 + 1].fX, points[i * 2 + 1].fY); - strokePath(); + SkPDFUtils::MoveTo(points[i * 2].fX, points[i * 2].fY, + &fContent); + SkPDFUtils::AppendLine(points[i * 2 + 1].fX, + points[i * 2 + 1].fY, &fContent); + SkPDFUtils::StrokePath(&fContent); } break; case SkCanvas::kPoints_PointMode: if (paint.getStrokeCap() == SkPaint::kRound_Cap) { updateGSFromPaint(paint, false); for (size_t i = 0; i < count; i++) { - moveTo(points[i].fX, points[i].fY); - strokePath(); + SkPDFUtils::MoveTo(points[i].fX, points[i].fY, &fContent); + SkPDFUtils::StrokePath(&fContent); } } else { // PDF won't draw a single point with square/butt caps because @@ -269,8 +265,10 @@ void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r, // Skia has 0,0 at top left, pdf at bottom left. Do the right thing. SkScalar bottom = r.fBottom < r.fTop ? r.fBottom : r.fTop; - appendRectangle(r.fLeft, bottom, r.width(), r.height()); - paintPath(paint.getStyle(), SkPath::kWinding_FillType); + SkPDFUtils::AppendRectangle(r.fLeft, bottom, r.width(), r.height(), + &fContent); + SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, + &fContent); } void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& path, @@ -290,8 +288,8 @@ void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& path, } updateGSFromPaint(paint, false); - emitPath(path); - paintPath(paint.getStyle(), path.getFillType()); + SkPDFUtils::EmitPath(path, &fContent); + SkPDFUtils::PaintPath(paint.getStyle(), path.getFillType(), &fContent); } void SkPDFDevice::drawBitmap(const SkDraw&, const SkBitmap& bitmap, @@ -630,25 +628,23 @@ void SkPDFDevice::updateGSFromPaint(const SkPaint& newPaint, bool forText) { } void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID) { - uint32_t fontID = SkTypeface::UniqueID(paint.getTypeface()); + SkTypeface* typeface = paint.getTypeface(); if (fGraphicStack[fGraphicStackIndex].fTextSize != paint.getTextSize() || fGraphicStack[fGraphicStackIndex].fFont == NULL || - fGraphicStack[fGraphicStackIndex].fFont->fontID() != fontID || + fGraphicStack[fGraphicStackIndex].fFont->typeface() != typeface || !fGraphicStack[fGraphicStackIndex].fFont->hasGlyph(glyphID)) { - int fontIndex = getFontResourceIndex(fontID, glyphID); + int fontIndex = getFontResourceIndex(typeface, glyphID); fContent.append("/F"); fContent.appendS32(fontIndex); fContent.append(" "); SkPDFScalar::Append(paint.getTextSize(), &fContent); - fContent.append(" Tf\n"); fGraphicStack[fGraphicStackIndex].fTextSize = paint.getTextSize(); fGraphicStack[fGraphicStackIndex].fFont = fFontResources[fontIndex]; } } - -int SkPDFDevice::getFontResourceIndex(uint32_t fontID, uint16_t glyphID) { - SkRefPtr<SkPDFFont> newFont = SkPDFFont::getFontResource(fontID, glyphID); +int SkPDFDevice::getFontResourceIndex(SkTypeface* typeface, uint16_t glyphID) { + SkRefPtr<SkPDFFont> newFont = SkPDFFont::getFontResource(typeface, glyphID); newFont->unref(); // getFontResource and SkRefPtr both took a ref. int resourceIndex = fFontResources.find(newFont.get()); if (resourceIndex < 0) { @@ -659,121 +655,6 @@ int SkPDFDevice::getFontResourceIndex(uint32_t fontID, uint16_t glyphID) { return resourceIndex; } -void SkPDFDevice::moveTo(SkScalar x, SkScalar y) { - SkPDFScalar::Append(x, &fContent); - fContent.append(" "); - SkPDFScalar::Append(y, &fContent); - fContent.append(" m\n"); -} - -void SkPDFDevice::appendLine(SkScalar x, SkScalar y) { - SkPDFScalar::Append(x, &fContent); - fContent.append(" "); - SkPDFScalar::Append(y, &fContent); - fContent.append(" l\n"); -} - -void SkPDFDevice::appendCubic(SkScalar ctl1X, SkScalar ctl1Y, - SkScalar ctl2X, SkScalar ctl2Y, - SkScalar dstX, SkScalar dstY) { - SkString cmd("y\n"); - SkPDFScalar::Append(ctl1X, &fContent); - fContent.append(" "); - SkPDFScalar::Append(ctl1Y, &fContent); - fContent.append(" "); - if (ctl2X != dstX || ctl2Y != dstY) { - cmd.set("c\n"); - SkPDFScalar::Append(ctl2X, &fContent); - fContent.append(" "); - SkPDFScalar::Append(ctl2Y, &fContent); - fContent.append(" "); - } - SkPDFScalar::Append(dstX, &fContent); - fContent.append(" "); - SkPDFScalar::Append(dstY, &fContent); - fContent.append(" "); - fContent.append(cmd); -} - -void SkPDFDevice::appendRectangle(SkScalar x, SkScalar y, - SkScalar w, SkScalar h) { - SkPDFScalar::Append(x, &fContent); - fContent.append(" "); - SkPDFScalar::Append(y, &fContent); - fContent.append(" "); - SkPDFScalar::Append(w, &fContent); - fContent.append(" "); - SkPDFScalar::Append(h, &fContent); - fContent.append(" re\n"); -} - -void SkPDFDevice::emitPath(const SkPath& path) { - SkPoint args[4]; - SkPath::Iter iter(path, false); - for (SkPath::Verb verb = iter.next(args); - verb != SkPath::kDone_Verb; - verb = iter.next(args)) { - // args gets all the points, even the implicit first point. - switch (verb) { - case SkPath::kMove_Verb: - moveTo(args[0].fX, args[0].fY); - break; - case SkPath::kLine_Verb: - appendLine(args[1].fX, args[1].fY); - break; - case SkPath::kQuad_Verb: { - // Convert quad to cubic (degree elevation). http://goo.gl/vS4i - const SkScalar three = SkIntToScalar(3); - args[1].scale(SkIntToScalar(2)); - SkScalar ctl1X = SkScalarDiv(args[0].fX + args[1].fX, three); - SkScalar ctl1Y = SkScalarDiv(args[0].fY + args[1].fY, three); - SkScalar ctl2X = SkScalarDiv(args[2].fX + args[1].fX, three); - SkScalar ctl2Y = SkScalarDiv(args[2].fY + args[1].fY, three); - appendCubic(ctl1X, ctl1Y, ctl2X, ctl2Y, args[2].fX, args[2].fY); - break; - } - case SkPath::kCubic_Verb: - appendCubic(args[1].fX, args[1].fY, args[2].fX, args[2].fY, - args[3].fX, args[3].fY); - break; - case SkPath::kClose_Verb: - closePath(); - break; - case SkPath::kDone_Verb: - break; - default: - SkASSERT(false); - break; - } - } -} - -void SkPDFDevice::closePath() { - fContent.append("h\n"); -} - -void SkPDFDevice::paintPath(SkPaint::Style style, SkPath::FillType fill) { - if (style == SkPaint::kFill_Style) - fContent.append("f"); - else if (style == SkPaint::kStrokeAndFill_Style) - fContent.append("B"); - else if (style == SkPaint::kStroke_Style) - fContent.append("S"); - - if (style != SkPaint::kStroke_Style) { - // Not supported yet. - NOT_IMPLEMENTED(fill == SkPath::kInverseEvenOdd_FillType, false); - NOT_IMPLEMENTED(fill == SkPath::kInverseWinding_FillType, false); - if (fill == SkPath::kEvenOdd_FillType) - fContent.append("*"); - } - fContent.append("\n"); -} - -void SkPDFDevice::strokePath() { - paintPath(SkPaint::kStroke_Style, SkPath::kWinding_FillType); -} - void SkPDFDevice::pushGS() { SkASSERT(fGraphicStackIndex < 2); fContent.append("q\n"); diff --git a/src/pdf/SkPDFFont.cpp b/src/pdf/SkPDFFont.cpp index c7bbebac3f..2cbc243efa 100644 --- a/src/pdf/SkPDFFont.cpp +++ b/src/pdf/SkPDFFont.cpp @@ -17,11 +17,14 @@ #include <ctype.h> #include "SkFontHost.h" +#include "SkGlyphCache.h" #include "SkPaint.h" +#include "SkPDFDevice.h" #include "SkPDFFont.h" #include "SkPDFStream.h" -#include "SkAdvancedTypefaceMetrics.h" #include "SkPDFTypes.h" +#include "SkPDFUtils.h" +#include "SkScalar.h" #include "SkStream.h" #include "SkTypeface.h" #include "SkUtils.h" @@ -228,6 +231,36 @@ SkScalar scaleFromFontUnits(int16_t val, uint16_t emSize) { return SkIntToScalar(intVal) * SkScalarInvert(SkIntToScalar(emSize)); } +void setGlyphWidthAndBoundingBox(SkScalar width, SkIRect box, + SkString* content) { + // Specify width and bounding box for the glyph. + SkPDFScalar::Append(width, content); + content->appendf(" 0 %d %d %d %d d1\n", box.fLeft, box.fTop, + box.fRight, box.fBottom); +} + +SkPDFArray* makeFontBBox( + SkIRect glyphBBox, uint16_t emSize, + SkPDFDevice::OriginTransform flipOrigin = + SkPDFDevice::kNoFlip_OriginTransform) { + if (flipOrigin == SkPDFDevice::kFlip_OriginTransform) { + int32_t temp = -glyphBBox.fTop; + glyphBBox.fTop = -glyphBBox.fBottom; + glyphBBox.fBottom = temp; + } + SkPDFArray* bbox = new SkPDFArray; + bbox->reserve(4); + bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fLeft, + emSize)))->unref(); + bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fBottom, + emSize)))->unref(); + bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fRight, + emSize)))->unref(); + bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fTop, + emSize)))->unref(); + return bbox; +} + SkPDFArray* appendWidth(const int16_t& width, uint16_t emSize, SkPDFArray* array) { array->append(new SkPDFScalar(scaleFromFontUnits(width, emSize)))->unref(); @@ -297,7 +330,7 @@ SkPDFArray* composeAdvanceData( SkPDFFont::~SkPDFFont() { SkAutoMutexAcquire lock(canonicalFontsMutex()); int index; - if (find(fFontID, fFirstGlyphID, &index)) { + if (find(SkTypeface::UniqueID(fTypeface.get()), fFirstGlyphID, &index)) { canonicalFonts().removeShuffle(index); #ifdef SK_DEBUG SkASSERT(!fDescendant); @@ -317,8 +350,8 @@ void SkPDFFont::getResources(SkTDArray<SkPDFObject*>* resourceList) { } } -uint32_t SkPDFFont::fontID() { - return fFontID; +SkTypeface* SkPDFFont::typeface() { + return fTypeface.get(); } bool SkPDFFont::hasGlyph(uint16_t id) { @@ -350,8 +383,9 @@ size_t SkPDFFont::glyphsToPDFFontEncoding(uint16_t* glyphIDs, } // static -SkPDFFont* SkPDFFont::getFontResource(uint32_t fontID, uint16_t glyphID) { +SkPDFFont* SkPDFFont::getFontResource(SkTypeface* typeface, uint16_t glyphID) { SkAutoMutexAcquire lock(canonicalFontsMutex()); + const uint32_t fontID = SkTypeface::UniqueID(typeface); int index; if (find(fontID, glyphID, &index)) { canonicalFonts()[index].fFont->ref(); @@ -370,7 +404,7 @@ SkPDFFont* SkPDFFont::getFontResource(uint32_t fontID, uint16_t glyphID) { fontInfo->unref(); // SkRefPtr and get info both took a reference. } - SkPDFFont* font = new SkPDFFont(fontInfo.get(), fontID, glyphID, false, + SkPDFFont* font = new SkPDFFont(fontInfo.get(), typeface, glyphID, false, fontDescriptor); FontRec newEntry(font, fontID, font->fFirstGlyphID); index = canonicalFonts().count(); @@ -404,11 +438,13 @@ bool SkPDFFont::find(uint32_t fontID, uint16_t glyphID, int* index) { return false; } -SkPDFFont::SkPDFFont(class SkAdvancedTypefaceMetrics* fontInfo, uint32_t fontID, - uint16_t glyphID, bool descendantFont, +SkPDFFont::SkPDFFont(class SkAdvancedTypefaceMetrics* fontInfo, + SkTypeface* typeface, + uint16_t glyphID, + bool descendantFont, SkPDFDict* fontDescriptor) : SkPDFDict("Font"), - fFontID(fontID), + fTypeface(typeface), #ifdef SK_DEBUG fDescendant(descendantFont), #endif @@ -420,39 +456,37 @@ SkPDFFont::SkPDFFont(class SkAdvancedTypefaceMetrics* fontInfo, uint32_t fontID, if (fontInfo->fMultiMaster) { SkASSERT(false); // Not supported yet. - populateType3Font(); - } else { - switch (fontInfo->fType) { - case SkAdvancedTypefaceMetrics::kType1CID_Font: - case SkAdvancedTypefaceMetrics::kTrueType_Font: - if (descendantFont) - populateCIDFont(); - else - populateType0Font(); - break; - case SkAdvancedTypefaceMetrics::kType1_Font: { - uint16_t firstGlyphID = glyphID - (glyphID - 1) % 255; - uint16_t lastGlyphID = firstGlyphID + 255 - 1; - if (lastGlyphID > fLastGlyphID) - lastGlyphID = fLastGlyphID; - if (populateType1Font(firstGlyphID, lastGlyphID)) - break; - // else, fall through. - } - case SkAdvancedTypefaceMetrics::kOther_Font: - case SkAdvancedTypefaceMetrics::kNotEmbeddable_Font: - populateType3Font(); - break; - case SkAdvancedTypefaceMetrics::kCFF_Font: - SkASSERT(false); // Not supported yet. - populateType3Font(); - break; + fontInfo->fType = SkAdvancedTypefaceMetrics::kOther_Font; + } + if (fontInfo->fType == SkAdvancedTypefaceMetrics::kType1CID_Font || + fontInfo->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) { + if (descendantFont) { + populateCIDFont(); + } else { + populateType0Font(); } + // No need to hold onto the font info for fonts types that + // support multibyte glyphs. + fFontInfo = NULL; + return; } - // Type1 fonts may hold on to the font info, otherwise we are done with it. - if (fontInfo->fType != SkAdvancedTypefaceMetrics::kType1_Font) - fFontInfo = NULL; + // Single byte glyph encoding supports a max of 255 glyphs. + fFirstGlyphID = glyphID - (glyphID - 1) % 255; + if (fLastGlyphID > fFirstGlyphID + 255 - 1) { + fLastGlyphID = fFirstGlyphID + 255 - 1; + } + + if (fontInfo->fType == SkAdvancedTypefaceMetrics::kType1_Font && + populateType1Font()) { + return; + } + + SkASSERT(fontInfo->fType == SkAdvancedTypefaceMetrics::kType1_Font || + fontInfo->fType == SkAdvancedTypefaceMetrics::kCFF_Font || + fontInfo->fType == SkAdvancedTypefaceMetrics::kOther_Font || + fontInfo->fType == SkAdvancedTypefaceMetrics::kNotEmbeddable_Font); + populateType3Font(); } void SkPDFFont::populateType0Font() { @@ -460,26 +494,26 @@ void SkPDFFont::populateType0Font() { fMultiByteGlyphs = true; insert("Subtype", new SkPDFName("Type0"))->unref(); - insert("BaseFont", new SkPDFName(fFontInfo.get()->fFontName))->unref(); + insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref(); insert("Encoding", new SkPDFName("Identity-H"))->unref(); SkRefPtr<SkPDFArray> descendantFonts = new SkPDFArray(); descendantFonts->unref(); // SkRefPtr and new took a reference. // Pass ref new created to fResources. - fResources.push(new SkPDFFont(fFontInfo.get(), fFontID, 1, true, NULL)); + fResources.push( + new SkPDFFont(fFontInfo.get(), fTypeface.get(), 1, true, NULL)); descendantFonts->append(new SkPDFObjRef(fResources.top()))->unref(); insert("DescendantFonts", descendantFonts.get()); } void SkPDFFont::populateCIDFont() { fMultiByteGlyphs = true; - insert("BaseFont", new SkPDFName(fFontInfo.get()->fFontName))->unref(); + insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref(); - if (fFontInfo.get()->fType == SkAdvancedTypefaceMetrics::kType1CID_Font) { + if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kType1CID_Font) { insert("Subtype", new SkPDFName("CIDFontType0"))->unref(); - } else if (fFontInfo.get()->fType == - SkAdvancedTypefaceMetrics::kTrueType_Font) { + } else if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kTrueType_Font) { insert("Subtype", new SkPDFName("CIDFontType2"))->unref(); } else { SkASSERT(false); @@ -494,29 +528,28 @@ void SkPDFFont::populateCIDFont() { addFontDescriptor(0); - if (fFontInfo.get()->fGlyphWidths.get()) { + if (fFontInfo->fGlyphWidths.get()) { int16_t defaultWidth = 0; SkRefPtr<SkPDFArray> widths = - composeAdvanceData(fFontInfo.get()->fGlyphWidths.get(), - fFontInfo.get()->fEmSize, &appendWidth, - &defaultWidth); + composeAdvanceData(fFontInfo->fGlyphWidths.get(), + fFontInfo->fEmSize, &appendWidth, &defaultWidth); widths->unref(); // SkRefPtr and compose both took a reference. if (widths->size()) insert("W", widths.get()); if (defaultWidth != 0) { insert("DW", new SkPDFScalar(scaleFromFontUnits( - defaultWidth, fFontInfo.get()->fEmSize)))->unref(); + defaultWidth, fFontInfo->fEmSize)))->unref(); } } - if (fFontInfo.get()->fVerticalMetrics.get()) { + if (fFontInfo->fVerticalMetrics.get()) { struct SkAdvancedTypefaceMetrics::VerticalMetric defaultAdvance; defaultAdvance.fVerticalAdvance = 0; defaultAdvance.fOriginXDisp = 0; defaultAdvance.fOriginYDisp = 0; SkRefPtr<SkPDFArray> advances = - composeAdvanceData(fFontInfo.get()->fVerticalMetrics.get(), - fFontInfo.get()->fEmSize, - &appendVerticalAdvance, &defaultAdvance); + composeAdvanceData(fFontInfo->fVerticalMetrics.get(), + fFontInfo->fEmSize, &appendVerticalAdvance, + &defaultAdvance); advances->unref(); // SkRefPtr and compose both took a ref. if (advances->size()) insert("W2", advances.get()); @@ -524,15 +557,15 @@ void SkPDFFont::populateCIDFont() { defaultAdvance.fOriginXDisp || defaultAdvance.fOriginYDisp) { insert("DW2", appendVerticalAdvance(defaultAdvance, - fFontInfo.get()->fEmSize, + fFontInfo->fEmSize, new SkPDFArray))->unref(); } } } -bool SkPDFFont::populateType1Font(uint16_t firstGlyphID, uint16_t lastGlyphID) { - SkASSERT(!fFontInfo.get()->fVerticalMetrics.get()); - SkASSERT(fFontInfo.get()->fGlyphWidths.get()); +bool SkPDFFont::populateType1Font() { + SkASSERT(!fFontInfo->fVerticalMetrics.get()); + SkASSERT(fFontInfo->fGlyphWidths.get()); int16_t defaultWidth = 0; const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry = NULL; @@ -557,37 +590,10 @@ bool SkPDFFont::populateType1Font(uint16_t firstGlyphID, uint16_t lastGlyphID) { if (!addFontDescriptor(defaultWidth)) return false; - fFirstGlyphID = firstGlyphID; - fLastGlyphID = lastGlyphID; - insert("Subtype", new SkPDFName("Type1"))->unref(); - insert("BaseFont", new SkPDFName(fFontInfo.get()->fFontName))->unref(); + insert("BaseFont", new SkPDFName(fFontInfo->fFontName))->unref(); - const uint16_t emSize = fFontInfo.get()->fEmSize; - SkRefPtr<SkPDFArray> widthArray = new SkPDFArray(); - widthArray->unref(); // SkRefPtr and new both took a ref. - int firstChar = 0; - if (widthRangeEntry) { - int startIndex = firstGlyphID - widthRangeEntry->fStartId; - int endIndex = startIndex + lastGlyphID - firstGlyphID + 1; - if (startIndex < 0) - startIndex = 0; - if (endIndex > widthRangeEntry->fAdvance.count()) - endIndex = widthRangeEntry->fAdvance.count(); - if (widthRangeEntry->fStartId == 0) { - appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get()); - } else { - firstChar = startIndex + widthRangeEntry->fStartId; - } - for (int i = startIndex; i < endIndex; i++) - appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get()); - } else { - appendWidth(defaultWidth, emSize, widthArray.get()); - } - insert("Widths", widthArray.get()); - insert("FirstChar", new SkPDFInt(firstChar))->unref(); - insert("LastChar", - new SkPDFInt(firstChar + widthArray->size() - 1))->unref(); + addWidthInfoFromRange(defaultWidth, widthRangeEntry); SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding"); encoding->unref(); // SkRefPtr and new both took a reference. @@ -601,17 +607,83 @@ bool SkPDFFont::populateType1Font(uint16_t firstGlyphID, uint16_t lastGlyphID) { encDiffs->append(new SkPDFInt(1))->unref(); for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) { encDiffs->append( - new SkPDFName(fFontInfo.get()->fGlyphNames->get()[gID]))->unref(); + new SkPDFName(fFontInfo->fGlyphNames->get()[gID]))->unref(); } - if (fFontInfo.get()->fLastGlyphID <= 255) + if (fFontInfo->fLastGlyphID <= 255) fFontInfo = NULL; return true; } void SkPDFFont::populateType3Font() { - // TODO(vandebo) - SkASSERT(false); + insert("Subtype", new SkPDFName("Type3"))->unref(); + // Flip about the x-axis and scale by 1/1000. + SkMatrix fontMatrix; + fontMatrix.setScale(SkScalarInvert(1000), -SkScalarInvert(1000)); + insert("FontMatrix", SkPDFUtils::MatrixToArray(fontMatrix))->unref(); + + SkRefPtr<SkPDFDict> charProcs = new SkPDFDict; + charProcs->unref(); // SkRefPtr and new both took a reference. + insert("CharProcs", charProcs.get()); + + SkRefPtr<SkPDFDict> encoding = new SkPDFDict("Encoding"); + encoding->unref(); // SkRefPtr and new both took a reference. + insert("Encoding", encoding.get()); + + SkRefPtr<SkPDFArray> encDiffs = new SkPDFArray; + encDiffs->unref(); // SkRefPtr and new both took a reference. + encoding->insert("Differences", encDiffs.get()); + encDiffs->reserve(fLastGlyphID - fFirstGlyphID + 2); + encDiffs->append(new SkPDFInt(1))->unref(); + + SkRefPtr<SkPDFArray> widthArray = new SkPDFArray(); + widthArray->unref(); // SkRefPtr and new both took a ref. + + SkPaint paint; + paint.setTypeface(fTypeface.get()); + paint.setTextSize(1000); + SkAutoGlyphCache autoCache(paint, NULL); + SkGlyphCache* cache = autoCache.getCache(); + + SkIRect bbox = SkIRect::MakeEmpty(); + for (int gID = fFirstGlyphID; gID <= fLastGlyphID; gID++) { + SkString characterName; + characterName.printf("gid%d", gID); + encDiffs->append(new SkPDFName(characterName))->unref(); + + const SkGlyph glyph = cache->getGlyphIDMetrics(gID); + appendWidth(SkFixedToFloat(glyph.fAdvanceX), 1000, widthArray.get()); + SkIRect glyphBBox = SkIRect::MakeXYWH(glyph.fLeft, glyph.fTop, + glyph.fWidth, glyph.fHeight); + bbox.join(glyphBBox); + + SkString content; + setGlyphWidthAndBoundingBox(SkFixedToScalar(glyph.fAdvanceX), glyphBBox, + &content); + const SkPath* path = cache->findPath(glyph); + if (path) { + SkPDFUtils::EmitPath(*path, &content); + SkPDFUtils::PaintPath(paint.getStyle(), path->getFillType(), + &content); + } + SkRefPtr<SkStream> glyphStream = + new SkMemoryStream(content.c_str(), content.size(), true); + glyphStream->unref(); // SkRefPtr and new both took a ref. + SkRefPtr<SkPDFStream> glyphDescription = + new SkPDFStream(glyphStream.get()); + // SkRefPtr and new both ref()'d charProcs, pass one. + fResources.push(glyphDescription.get()); + charProcs->insert(characterName.c_str(), + new SkPDFObjRef(glyphDescription.get()))->unref(); + } + + insert("FontBBox", makeFontBBox(bbox, 1000))->unref(); + insert("FirstChar", new SkPDFInt(fFirstGlyphID))->unref(); + insert("LastChar", new SkPDFInt(fLastGlyphID))->unref(); + insert("Widths", widthArray.get()); + + if (fFontInfo->fLastGlyphID <= 255) + fFontInfo = NULL; } bool SkPDFFont::addFontDescriptor(int16_t defaultWidth) { @@ -625,11 +697,11 @@ bool SkPDFFont::addFontDescriptor(int16_t defaultWidth) { fDescriptor = new SkPDFDict("FontDescriptor"); fDescriptor->unref(); // SkRefPtr and new both took a ref. - switch (fFontInfo.get()->fType) { + switch (fFontInfo->fType) { case SkAdvancedTypefaceMetrics::kType1_Font: { size_t header, data, trailer; SkRefPtr<SkStream> rawFontData = - SkFontHost::OpenStream(fFontID); + SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get())); rawFontData->unref(); // SkRefPtr and OpenStream both took a ref. SkStream* fontData = handleType1Stream(rawFontData.get(), &header, &data, &trailer); @@ -646,7 +718,8 @@ bool SkPDFFont::addFontDescriptor(int16_t defaultWidth) { break; } case SkAdvancedTypefaceMetrics::kTrueType_Font: { - SkRefPtr<SkStream> fontData = SkFontHost::OpenStream(fFontID); + SkRefPtr<SkStream> fontData = + SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get())); fontData->unref(); // SkRefPtr and OpenStream both took a ref. SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get()); // SkRefPtr and new both ref()'d fontStream, pass one. @@ -660,14 +733,14 @@ bool SkPDFFont::addFontDescriptor(int16_t defaultWidth) { } case SkAdvancedTypefaceMetrics::kCFF_Font: case SkAdvancedTypefaceMetrics::kType1CID_Font: { - SkRefPtr<SkStream> fontData = SkFontHost::OpenStream(fFontID); + SkRefPtr<SkStream> fontData = + SkFontHost::OpenStream(SkTypeface::UniqueID(fTypeface.get())); fontData->unref(); // SkRefPtr and OpenStream both took a ref. SkRefPtr<SkPDFStream> fontStream = new SkPDFStream(fontData.get()); // SkRefPtr and new both ref()'d fontStream, pass one. fResources.push(fontStream.get()); - if (fFontInfo.get()->fType == - SkAdvancedTypefaceMetrics::kCFF_Font) { + if (fFontInfo->fType == SkAdvancedTypefaceMetrics::kCFF_Font) { fontStream->insert("Subtype", new SkPDFName("Type1C"))->unref(); } else { fontStream->insert("Subtype", @@ -681,39 +754,26 @@ bool SkPDFFont::addFontDescriptor(int16_t defaultWidth) { SkASSERT(false); } - const uint16_t emSize = fFontInfo.get()->fEmSize; + const uint16_t emSize = fFontInfo->fEmSize; fResources.push(fDescriptor.get()); fDescriptor->ref(); insert("FontDescriptor", new SkPDFObjRef(fDescriptor.get()))->unref(); fDescriptor->insert("FontName", new SkPDFName( - fFontInfo.get()->fFontName))->unref(); - fDescriptor->insert("Flags", new SkPDFInt( - fFontInfo.get()->fStyle))->unref(); + fFontInfo->fFontName))->unref(); + fDescriptor->insert("Flags", new SkPDFInt(fFontInfo->fStyle))->unref(); fDescriptor->insert("Ascent", new SkPDFScalar( - scaleFromFontUnits(fFontInfo.get()->fAscent, emSize)))->unref(); + scaleFromFontUnits(fFontInfo->fAscent, emSize)))->unref(); fDescriptor->insert("Descent", new SkPDFScalar( - scaleFromFontUnits(fFontInfo.get()->fDescent, emSize)))->unref(); + scaleFromFontUnits(fFontInfo->fDescent, emSize)))->unref(); fDescriptor->insert("StemV", new SkPDFScalar( - scaleFromFontUnits(fFontInfo.get()->fStemV, emSize)))->unref(); + scaleFromFontUnits(fFontInfo->fStemV, emSize)))->unref(); fDescriptor->insert("CapHeight", new SkPDFScalar( - scaleFromFontUnits(fFontInfo.get()->fCapHeight, emSize)))->unref(); + scaleFromFontUnits(fFontInfo->fCapHeight, emSize)))->unref(); fDescriptor->insert("ItalicAngle", new SkPDFInt( - fFontInfo.get()->fItalicAngle))->unref(); - - SkIRect glyphBBox = fFontInfo.get()->fBBox; - SkRefPtr<SkPDFArray> bbox = new SkPDFArray; - bbox->unref(); // SkRefPtr and new both took a reference. - bbox->reserve(4); - bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fLeft, - emSize)))->unref(); - bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fBottom, - emSize)))->unref(); - bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fRight, - emSize)))->unref(); - bbox->append(new SkPDFScalar(scaleFromFontUnits(glyphBBox.fTop, - emSize)))->unref(); - fDescriptor->insert("FontBBox", bbox.get()); + fFontInfo->fItalicAngle))->unref(); + fDescriptor->insert("FontBBox", makeFontBBox(fFontInfo->fBBox, + fFontInfo->fEmSize))->unref(); if (defaultWidth > 0) { fDescriptor->insert("MissingWidth", new SkPDFScalar( @@ -721,7 +781,35 @@ bool SkPDFFont::addFontDescriptor(int16_t defaultWidth) { } return true; } - +void SkPDFFont::addWidthInfoFromRange( + int16_t defaultWidth, + const SkAdvancedTypefaceMetrics::WidthRange* widthRangeEntry) { + SkRefPtr<SkPDFArray> widthArray = new SkPDFArray(); + widthArray->unref(); // SkRefPtr and new both took a ref. + int firstChar = 0; + if (widthRangeEntry) { + const uint16_t emSize = fFontInfo->fEmSize; + int startIndex = fFirstGlyphID - widthRangeEntry->fStartId; + int endIndex = startIndex + fLastGlyphID - fFirstGlyphID + 1; + if (startIndex < 0) + startIndex = 0; + if (endIndex > widthRangeEntry->fAdvance.count()) + endIndex = widthRangeEntry->fAdvance.count(); + if (widthRangeEntry->fStartId == 0) { + appendWidth(widthRangeEntry->fAdvance[0], emSize, widthArray.get()); + } else { + firstChar = startIndex + widthRangeEntry->fStartId; + } + for (int i = startIndex; i < endIndex; i++) + appendWidth(widthRangeEntry->fAdvance[i], emSize, widthArray.get()); + } else { + appendWidth(defaultWidth, 1000, widthArray.get()); + } + insert("FirstChar", new SkPDFInt(firstChar))->unref(); + insert("LastChar", + new SkPDFInt(firstChar + widthArray->size() - 1))->unref(); + insert("Widths", widthArray.get()); +} bool SkPDFFont::FontRec::operator==(const SkPDFFont::FontRec& b) const { if (fFontID != b.fFontID) diff --git a/src/pdf/pdf_files.mk b/src/pdf/pdf_files.mk index 149e802c2a..ededdd35cd 100644 --- a/src/pdf/pdf_files.mk +++ b/src/pdf/pdf_files.mk @@ -8,4 +8,5 @@ SOURCE := \ SkPDFImage.cpp \ SkPDFPage.cpp \ SkPDFStream.cpp \ - SkPDFTypes.cpp + SkPDFTypes.cpp \ + SkPDFUtils.cpp diff --git a/src/ports/SkFontHost_win.cpp b/src/ports/SkFontHost_win.cpp index bf658272fd..a20f001efb 100644 --- a/src/ports/SkFontHost_win.cpp +++ b/src/ports/SkFontHost_win.cpp @@ -552,6 +552,10 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( const unsigned glyphCount = calculateGlyphCount(hdc);
info = new SkAdvancedTypefaceMetrics;
+ info->fEmSize = otm.otmEMSquare;
+ info->fMultiMaster = false;
+ info->fLastGlyphID = SkToU16(glyphCount - 1);
+ info->fStyle = 0;
#ifdef UNICODE
// Get the buffer size needed first.
size_t str_len = WideCharToMultiByte(CP_UTF8, 0, lf.lfFaceName, -1, NULL,
@@ -571,12 +575,15 @@ SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics( info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font;
} else {
info->fType = SkAdvancedTypefaceMetrics::kOther_Font;
+ info->fItalicAngle = 0;
+ info->fAscent = 0;
+ info->fDescent = 0;
+ info->fStemV = 0;
+ info->fCapHeight = 0;
+ info->fBBox = SkIRect::MakeEmpty();
+ return info;
}
- info->fEmSize = otm.otmEMSquare;
- info->fMultiMaster = false;
- info->fLastGlyphID = SkToU16(glyphCount - 1);
-
- info->fStyle = 0;
+
// If this bit is clear the font is a fixed pitch font.
if (!(otm.otmTextMetrics.tmPitchAndFamily & TMPF_FIXED_PITCH)) {
info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style;
|