OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkPDFDevice.h" | 8 #include "SkPDFDevice.h" |
9 | 9 |
10 #include "SkAnnotationKeys.h" | 10 #include "SkAnnotationKeys.h" |
(...skipping 637 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
648 }; | 648 }; |
649 | 649 |
650 //////////////////////////////////////////////////////////////////////////////// | 650 //////////////////////////////////////////////////////////////////////////////// |
651 | 651 |
652 SkPDFDevice::SkPDFDevice(SkISize pageSize, SkScalar rasterDpi, SkPDFDocument* do
c, bool flip) | 652 SkPDFDevice::SkPDFDevice(SkISize pageSize, SkScalar rasterDpi, SkPDFDocument* do
c, bool flip) |
653 : INHERITED(SkSurfaceProps(0, kUnknown_SkPixelGeometry)) | 653 : INHERITED(SkSurfaceProps(0, kUnknown_SkPixelGeometry)) |
654 , fPageSize(pageSize) | 654 , fPageSize(pageSize) |
655 , fContentSize(pageSize) | 655 , fContentSize(pageSize) |
656 , fExistingClipRegion(SkIRect::MakeSize(pageSize)) | 656 , fExistingClipRegion(SkIRect::MakeSize(pageSize)) |
657 , fClipStack(nullptr) | 657 , fClipStack(nullptr) |
658 , fFontGlyphUsage(new SkPDFGlyphSetMap) | |
659 , fRasterDpi(rasterDpi) | 658 , fRasterDpi(rasterDpi) |
660 , fDocument(doc) { | 659 , fDocument(doc) { |
661 SkASSERT(pageSize.width() > 0); | 660 SkASSERT(pageSize.width() > 0); |
662 SkASSERT(pageSize.height() > 0); | 661 SkASSERT(pageSize.height() > 0); |
663 fLegacyBitmap.setInfo( | 662 fLegacyBitmap.setInfo( |
664 SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height())); | 663 SkImageInfo::MakeUnknown(pageSize.width(), pageSize.height())); |
665 if (flip) { | 664 if (flip) { |
666 // Skia generally uses the top left as the origin but PDF | 665 // Skia generally uses the top left as the origin but PDF |
667 // natively has the origin at the bottom left. This matrix | 666 // natively has the origin at the bottom left. This matrix |
668 // corrects for that. But that only needs to be done once, we | 667 // corrects for that. But that only needs to be done once, we |
669 // don't do it when layering. | 668 // don't do it when layering. |
670 fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); | 669 fInitialTransform.setTranslate(0, SkIntToScalar(pageSize.fHeight)); |
671 fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); | 670 fInitialTransform.preScale(SK_Scalar1, -SK_Scalar1); |
672 } else { | 671 } else { |
673 fInitialTransform.setIdentity(); | 672 fInitialTransform.setIdentity(); |
674 } | 673 } |
675 } | 674 } |
676 | 675 |
677 SkPDFDevice::~SkPDFDevice() { | 676 SkPDFDevice::~SkPDFDevice() { |
678 this->cleanUp(true); | 677 this->cleanUp(); |
679 } | 678 } |
680 | 679 |
681 void SkPDFDevice::init() { | 680 void SkPDFDevice::init() { |
682 fContentEntries.reset(); | 681 fContentEntries.reset(); |
683 if (fFontGlyphUsage.get() == nullptr) { | |
684 fFontGlyphUsage.reset(new SkPDFGlyphSetMap); | |
685 } | |
686 } | 682 } |
687 | 683 |
688 void SkPDFDevice::cleanUp(bool clearFontUsage) { | 684 void SkPDFDevice::cleanUp() { |
689 fGraphicStateResources.unrefAll(); | 685 fGraphicStateResources.unrefAll(); |
690 fXObjectResources.unrefAll(); | 686 fXObjectResources.unrefAll(); |
691 fFontResources.unrefAll(); | 687 fFontResources.unrefAll(); |
692 fShaderResources.unrefAll(); | 688 fShaderResources.unrefAll(); |
693 | |
694 if (clearFontUsage) { | |
695 fFontGlyphUsage->reset(); | |
696 } | |
697 } | 689 } |
698 | 690 |
699 void SkPDFDevice::drawAnnotation(const SkDraw& d, const SkRect& rect, const char
key[], | 691 void SkPDFDevice::drawAnnotation(const SkDraw& d, const SkRect& rect, const char
key[], |
700 SkData* value) { | 692 SkData* value) { |
701 if (0 == rect.width() && 0 == rect.height()) { | 693 if (0 == rect.width() && 0 == rect.height()) { |
702 handlePointAnnotation({ rect.x(), rect.y() }, *d.fMatrix, key, value); | 694 handlePointAnnotation({ rect.x(), rect.y() }, *d.fMatrix, key, value); |
703 } else { | 695 } else { |
704 SkPath path; | 696 SkPath path; |
705 path.addRect(rect); | 697 path.addRect(rect); |
706 handlePathAnnotation(path, d, key, value); | 698 handlePathAnnotation(path, d, key, value); |
(...skipping 460 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1167 | 1159 |
1168 SkPaint::GlyphCacheProc glyphCacheProc = textPaint.getGlyphCacheProc(true); | 1160 SkPaint::GlyphCacheProc glyphCacheProc = textPaint.getGlyphCacheProc(true); |
1169 align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y); | 1161 align_text(glyphCacheProc, textPaint, glyphIDs, numGlyphs, &x, &y); |
1170 content.entry()->fContent.writeText("BT\n"); | 1162 content.entry()->fContent.writeText("BT\n"); |
1171 set_text_transform(x, y, textPaint.getTextSkewX(), | 1163 set_text_transform(x, y, textPaint.getTextSkewX(), |
1172 &content.entry()->fContent); | 1164 &content.entry()->fContent); |
1173 int consumedGlyphCount = 0; | 1165 int consumedGlyphCount = 0; |
1174 | 1166 |
1175 SkTDArray<uint16_t> glyphIDsCopy(glyphIDs, numGlyphs); | 1167 SkTDArray<uint16_t> glyphIDsCopy(glyphIDs, numGlyphs); |
1176 | 1168 |
| 1169 SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage(); |
| 1170 |
1177 while (numGlyphs > consumedGlyphCount) { | 1171 while (numGlyphs > consumedGlyphCount) { |
1178 this->updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry(
)); | 1172 this->updateFont(textPaint, glyphIDs[consumedGlyphCount], content.entry(
)); |
1179 SkPDFFont* font = content.entry()->fState.fFont; | 1173 SkPDFFont* font = content.entry()->fState.fFont; |
1180 | 1174 |
1181 int availableGlyphs = font->glyphsToPDFFontEncoding( | 1175 int availableGlyphs = font->glyphsToPDFFontEncoding( |
1182 glyphIDsCopy.begin() + consumedGlyphCount, | 1176 glyphIDsCopy.begin() + consumedGlyphCount, |
1183 numGlyphs - consumedGlyphCount); | 1177 numGlyphs - consumedGlyphCount); |
1184 fFontGlyphUsage->noteGlyphUsage( | 1178 fontGlyphUsage->noteGlyphUsage( |
1185 font, glyphIDsCopy.begin() + consumedGlyphCount, | 1179 font, glyphIDsCopy.begin() + consumedGlyphCount, |
1186 availableGlyphs); | 1180 availableGlyphs); |
1187 write_wide_string(&content.entry()->fContent, | 1181 write_wide_string(&content.entry()->fContent, |
1188 glyphIDsCopy.begin() + consumedGlyphCount, | 1182 glyphIDsCopy.begin() + consumedGlyphCount, |
1189 availableGlyphs, font->multiByteGlyphs()); | 1183 availableGlyphs, font->multiByteGlyphs()); |
1190 consumedGlyphCount += availableGlyphs; | 1184 consumedGlyphCount += availableGlyphs; |
1191 content.entry()->fContent.writeText(" Tj\n"); | 1185 content.entry()->fContent.writeText(" Tj\n"); |
1192 } | 1186 } |
1193 content.entry()->fContent.writeText("ET\n"); | 1187 content.entry()->fContent.writeText("ET\n"); |
1194 } | 1188 } |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1236 } | 1230 } |
1237 | 1231 |
1238 SkGlyphStorage storage(0); | 1232 SkGlyphStorage storage(0); |
1239 const uint16_t* glyphIDs = nullptr; | 1233 const uint16_t* glyphIDs = nullptr; |
1240 size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphID
s); | 1234 size_t numGlyphs = force_glyph_encoding(paint, text, len, &storage, &glyphID
s); |
1241 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 1235 textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
1242 | 1236 |
1243 SkPaint::GlyphCacheProc glyphCacheProc = textPaint.getGlyphCacheProc(true); | 1237 SkPaint::GlyphCacheProc glyphCacheProc = textPaint.getGlyphCacheProc(true); |
1244 content.entry()->fContent.writeText("BT\n"); | 1238 content.entry()->fContent.writeText("BT\n"); |
1245 this->updateFont(textPaint, glyphIDs[0], content.entry()); | 1239 this->updateFont(textPaint, glyphIDs[0], content.entry()); |
| 1240 SkPDFGlyphSetMap* fontGlyphUsage = fDocument->getGlyphUsage(); |
1246 for (size_t i = 0; i < numGlyphs; i++) { | 1241 for (size_t i = 0; i < numGlyphs; i++) { |
1247 SkPDFFont* font = content.entry()->fState.fFont; | 1242 SkPDFFont* font = content.entry()->fState.fFont; |
1248 uint16_t encodedValue = glyphIDs[i]; | 1243 uint16_t encodedValue = glyphIDs[i]; |
1249 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { | 1244 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { |
1250 // The current pdf font cannot encode the current glyph. | 1245 // The current pdf font cannot encode the current glyph. |
1251 // Try to get a pdf font which can encode the current glyph. | 1246 // Try to get a pdf font which can encode the current glyph. |
1252 this->updateFont(textPaint, glyphIDs[i], content.entry()); | 1247 this->updateFont(textPaint, glyphIDs[i], content.entry()); |
1253 font = content.entry()->fState.fFont; | 1248 font = content.entry()->fState.fFont; |
1254 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { | 1249 if (font->glyphsToPDFFontEncoding(&encodedValue, 1) != 1) { |
1255 SkDEBUGFAIL("PDF could not encode glyph."); | 1250 SkDEBUGFAIL("PDF could not encode glyph."); |
1256 continue; | 1251 continue; |
1257 } | 1252 } |
1258 } | 1253 } |
1259 | 1254 |
1260 fFontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1); | 1255 fontGlyphUsage->noteGlyphUsage(font, &encodedValue, 1); |
1261 SkScalar x = offset.x() + pos[i * scalarsPerPos]; | 1256 SkScalar x = offset.x() + pos[i * scalarsPerPos]; |
1262 SkScalar y = offset.y() + (2 == scalarsPerPos ? pos[i * scalarsPerPos +
1] : 0); | 1257 SkScalar y = offset.y() + (2 == scalarsPerPos ? pos[i * scalarsPerPos +
1] : 0); |
1263 | 1258 |
1264 align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y); | 1259 align_text(glyphCacheProc, textPaint, glyphIDs + i, 1, &x, &y); |
1265 set_text_transform(x, y, textPaint.getTextSkewX(), &content.entry()->fCo
ntent); | 1260 set_text_transform(x, y, textPaint.getTextSkewX(), &content.entry()->fCo
ntent); |
1266 write_wide_string(&content.entry()->fContent, &encodedValue, 1, | 1261 write_wide_string(&content.entry()->fContent, &encodedValue, 1, |
1267 font->multiByteGlyphs()); | 1262 font->multiByteGlyphs()); |
1268 content.entry()->fContent.writeText(" Tj\n"); | 1263 content.entry()->fContent.writeText(" Tj\n"); |
1269 } | 1264 } |
1270 content.entry()->fContent.writeText("ET\n"); | 1265 content.entry()->fContent.writeText("ET\n"); |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1318 SkIntToScalar(device->height()))); | 1313 SkIntToScalar(device->height()))); |
1319 content.setShape(shape); | 1314 content.setShape(shape); |
1320 } | 1315 } |
1321 if (!content.needSource()) { | 1316 if (!content.needSource()) { |
1322 return; | 1317 return; |
1323 } | 1318 } |
1324 | 1319 |
1325 auto xObject = sk_make_sp<SkPDFFormXObject>(pdfDevice); | 1320 auto xObject = sk_make_sp<SkPDFFormXObject>(pdfDevice); |
1326 SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()), | 1321 SkPDFUtils::DrawFormXObject(this->addXObjectResource(xObject.get()), |
1327 &content.entry()->fContent); | 1322 &content.entry()->fContent); |
1328 | |
1329 // Merge glyph sets from the drawn device. | |
1330 fFontGlyphUsage->merge(pdfDevice->getFontGlyphUsage()); | |
1331 } | 1323 } |
1332 | 1324 |
1333 SkImageInfo SkPDFDevice::imageInfo() const { | 1325 SkImageInfo SkPDFDevice::imageInfo() const { |
1334 return fLegacyBitmap.info(); | 1326 return fLegacyBitmap.info(); |
1335 } | 1327 } |
1336 | 1328 |
1337 void SkPDFDevice::onAttachToCanvas(SkCanvas* canvas) { | 1329 void SkPDFDevice::onAttachToCanvas(SkCanvas* canvas) { |
1338 INHERITED::onAttachToCanvas(canvas); | 1330 INHERITED::onAttachToCanvas(canvas); |
1339 | 1331 |
1340 // Canvas promises that this ptr is valid until onDetachFromCanvas is called | 1332 // Canvas promises that this ptr is valid until onDetachFromCanvas is called |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1551 SkString name(static_cast<const char*>(dest.nameData->data())); | 1543 SkString name(static_cast<const char*>(dest.nameData->data())); |
1552 dict->insertObject(name, std::move(pdfDest)); | 1544 dict->insertObject(name, std::move(pdfDest)); |
1553 } | 1545 } |
1554 } | 1546 } |
1555 | 1547 |
1556 SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() { | 1548 SkPDFFormXObject* SkPDFDevice::createFormXObjectFromDevice() { |
1557 SkPDFFormXObject* xobject = new SkPDFFormXObject(this); | 1549 SkPDFFormXObject* xobject = new SkPDFFormXObject(this); |
1558 // We always draw the form xobjects that we create back into the device, so | 1550 // We always draw the form xobjects that we create back into the device, so |
1559 // we simply preserve the font usage instead of pulling it out and merging | 1551 // we simply preserve the font usage instead of pulling it out and merging |
1560 // it back in later. | 1552 // it back in later. |
1561 cleanUp(false); // Reset this device to have no content. | 1553 cleanUp(); // Reset this device to have no content. |
1562 init(); | 1554 init(); |
1563 return xobject; | 1555 return xobject; |
1564 } | 1556 } |
1565 | 1557 |
1566 void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, | 1558 void SkPDFDevice::drawFormXObjectWithMask(int xObjectIndex, |
1567 SkPDFFormXObject* mask, | 1559 SkPDFFormXObject* mask, |
1568 const SkClipStack* clipStack, | 1560 const SkClipStack* clipStack, |
1569 const SkRegion& clipRegion, | 1561 const SkRegion& clipRegion, |
1570 SkXfermode::Mode mode, | 1562 SkXfermode::Mode mode, |
1571 bool invertClip) { | 1563 bool invertClip) { |
(...skipping 564 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2136 if (!pdfimage) { | 2128 if (!pdfimage) { |
2137 return; | 2129 return; |
2138 } | 2130 } |
2139 fDocument->serialize(pdfimage); // serialize images early. | 2131 fDocument->serialize(pdfimage); // serialize images early. |
2140 fDocument->canon()->addPDFBitmap(key, pdfimage); | 2132 fDocument->canon()->addPDFBitmap(key, pdfimage); |
2141 } | 2133 } |
2142 // TODO(halcanary): addXObjectResource() should take a sk_sp<SkPDFObject> | 2134 // TODO(halcanary): addXObjectResource() should take a sk_sp<SkPDFObject> |
2143 SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), | 2135 SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), |
2144 &content.entry()->fContent); | 2136 &content.entry()->fContent); |
2145 } | 2137 } |
OLD | NEW |