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