| 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 <tuple> |
| 8 #include "SkPDFDevice.h" | 9 #include "SkPDFDevice.h" |
| 9 | 10 |
| 10 #include "SkAnnotation.h" | 11 #include "SkAnnotation.h" |
| 11 #include "SkColor.h" | 12 #include "SkColor.h" |
| 12 #include "SkColorFilter.h" | 13 #include "SkColorFilter.h" |
| 13 #include "SkClipStack.h" | 14 #include "SkClipStack.h" |
| 14 #include "SkData.h" | 15 #include "SkData.h" |
| 15 #include "SkDraw.h" | 16 #include "SkDraw.h" |
| 16 #include "SkGlyphCache.h" | 17 #include "SkGlyphCache.h" |
| 17 #include "SkPaint.h" | 18 #include "SkPaint.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 34 #include "SkSurface.h" | 35 #include "SkSurface.h" |
| 35 #include "SkTextFormatParams.h" | 36 #include "SkTextFormatParams.h" |
| 36 #include "SkTemplates.h" | 37 #include "SkTemplates.h" |
| 37 #include "SkTypefacePriv.h" | 38 #include "SkTypefacePriv.h" |
| 38 #include "SkXfermodeInterpretation.h" | 39 #include "SkXfermodeInterpretation.h" |
| 39 | 40 |
| 40 #define DPI_FOR_RASTER_SCALE_ONE 72 | 41 #define DPI_FOR_RASTER_SCALE_ONE 72 |
| 41 | 42 |
| 42 // Utility functions | 43 // Utility functions |
| 43 | 44 |
| 45 static bool excessive_translation(const SkMatrix& m) { |
| 46 const SkScalar kExcessiveTranslation = 8192.0f; |
| 47 return SkScalarAbs(m.getTranslateX()) > kExcessiveTranslation |
| 48 || SkScalarAbs(m.getTranslateY()) > kExcessiveTranslation; |
| 49 } |
| 50 |
| 51 static std::tuple<SkMatrix, SkVector> untranslate(const SkDraw& d) { |
| 52 // https://bug.skia.org/257 If the translation is too large, |
| 53 // PDF can't exactly represent the float values as numbers. |
| 54 SkScalar translateX = d.fMatrix->getTranslateX() / d.fMatrix->getScaleX(); |
| 55 SkScalar translateY = d.fMatrix->getTranslateY() / d.fMatrix->getScaleY(); |
| 56 SkMatrix mat = *d.fMatrix; |
| 57 mat.preTranslate(-translateX, -translateY); |
| 58 SkASSERT(SkScalarAbs(mat.getTranslateX()) <= 1.0); |
| 59 return std::make_tuple(mat, SkVector::Make(translateX, translateY)); |
| 60 } |
| 61 |
| 44 // If the paint will definitely draw opaquely, replace kSrc_Mode with | 62 // If the paint will definitely draw opaquely, replace kSrc_Mode with |
| 45 // kSrcOver_Mode. http://crbug.com/473572 | 63 // kSrcOver_Mode. http://crbug.com/473572 |
| 46 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { | 64 static void replace_srcmode_on_opaque_paint(SkPaint* paint) { |
| 47 if (kSrcOver_SkXfermodeInterpretation | 65 if (kSrcOver_SkXfermodeInterpretation |
| 48 == SkInterpretXfermode(*paint, false)) { | 66 == SkInterpretXfermode(*paint, false)) { |
| 49 paint->setXfermode(nullptr); | 67 paint->setXfermode(nullptr); |
| 50 } | 68 } |
| 51 } | 69 } |
| 52 | 70 |
| 53 static void emit_pdf_color(SkColor color, SkWStream* result) { | 71 static void emit_pdf_color(SkColor color, SkWStream* result) { |
| (...skipping 740 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 794 | 812 |
| 795 if (count == 0) { | 813 if (count == 0) { |
| 796 return; | 814 return; |
| 797 } | 815 } |
| 798 | 816 |
| 799 if (SkAnnotation* annotation = passedPaint.getAnnotation()) { | 817 if (SkAnnotation* annotation = passedPaint.getAnnotation()) { |
| 800 if (handlePointAnnotation(points, count, *d.fMatrix, annotation)) { | 818 if (handlePointAnnotation(points, count, *d.fMatrix, annotation)) { |
| 801 return; | 819 return; |
| 802 } | 820 } |
| 803 } | 821 } |
| 822 if (excessive_translation(*d.fMatrix)) { |
| 823 SkVector translate; SkMatrix translateMatrix; |
| 824 std::tie(translateMatrix, translate) = untranslate(d); |
| 825 SkDraw drawCopy(d); |
| 826 drawCopy.fMatrix = &translateMatrix; |
| 827 SkTArray<SkPoint> pointsCopy(points, SkToInt(count)); |
| 828 SkPoint::Offset(&pointsCopy[0], SkToInt(count), translate); |
| 829 this->drawPoints(drawCopy, mode, count, &pointsCopy[0], srcPaint); |
| 830 return; // NOTE: shader behavior will be off. |
| 831 } |
| 804 | 832 |
| 805 // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. | 833 // SkDraw::drawPoints converts to multiple calls to fDevice->drawPath. |
| 806 // We only use this when there's a path effect because of the overhead | 834 // We only use this when there's a path effect because of the overhead |
| 807 // of multiple calls to setUpContentEntry it causes. | 835 // of multiple calls to setUpContentEntry it causes. |
| 808 if (passedPaint.getPathEffect()) { | 836 if (passedPaint.getPathEffect()) { |
| 809 if (d.fClip->isEmpty()) { | 837 if (d.fClip->isEmpty()) { |
| 810 return; | 838 return; |
| 811 } | 839 } |
| 812 SkDraw pointDraw(d); | 840 SkDraw pointDraw(d); |
| 813 pointDraw.fDevice = this; | 841 pointDraw.fDevice = this; |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 922 } | 950 } |
| 923 | 951 |
| 924 void SkPDFDevice::drawRect(const SkDraw& d, | 952 void SkPDFDevice::drawRect(const SkDraw& d, |
| 925 const SkRect& rect, | 953 const SkRect& rect, |
| 926 const SkPaint& srcPaint) { | 954 const SkPaint& srcPaint) { |
| 927 SkPaint paint = srcPaint; | 955 SkPaint paint = srcPaint; |
| 928 replace_srcmode_on_opaque_paint(&paint); | 956 replace_srcmode_on_opaque_paint(&paint); |
| 929 SkRect r = rect; | 957 SkRect r = rect; |
| 930 r.sort(); | 958 r.sort(); |
| 931 | 959 |
| 960 if (excessive_translation(*d.fMatrix)) { |
| 961 SkVector translate; SkMatrix translateMatrix; |
| 962 std::tie(translateMatrix, translate) = untranslate(d); |
| 963 SkDraw drawCopy(d); |
| 964 drawCopy.fMatrix = &translateMatrix; |
| 965 SkRect rectCopy = rect; |
| 966 rectCopy.offset(translate.x(), translate.y()); |
| 967 this->drawRect(drawCopy, rectCopy, srcPaint); |
| 968 return; // NOTE: shader behavior will be off. |
| 969 } |
| 970 |
| 932 if (paint.getPathEffect()) { | 971 if (paint.getPathEffect()) { |
| 933 if (d.fClip->isEmpty()) { | 972 if (d.fClip->isEmpty()) { |
| 934 return; | 973 return; |
| 935 } | 974 } |
| 936 SkPath path; | 975 SkPath path; |
| 937 path.addRect(r); | 976 path.addRect(r); |
| 938 drawPath(d, path, paint, nullptr, true); | 977 drawPath(d, path, paint, nullptr, true); |
| 939 return; | 978 return; |
| 940 } | 979 } |
| 941 | 980 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 974 SkPath path; | 1013 SkPath path; |
| 975 path.addOval(oval); | 1014 path.addOval(oval); |
| 976 this->drawPath(draw, path, paint, nullptr, true); | 1015 this->drawPath(draw, path, paint, nullptr, true); |
| 977 } | 1016 } |
| 978 | 1017 |
| 979 void SkPDFDevice::drawPath(const SkDraw& d, | 1018 void SkPDFDevice::drawPath(const SkDraw& d, |
| 980 const SkPath& origPath, | 1019 const SkPath& origPath, |
| 981 const SkPaint& srcPaint, | 1020 const SkPaint& srcPaint, |
| 982 const SkMatrix* prePathMatrix, | 1021 const SkMatrix* prePathMatrix, |
| 983 bool pathIsMutable) { | 1022 bool pathIsMutable) { |
| 1023 if (excessive_translation(*d.fMatrix)) { |
| 1024 SkVector translate; SkMatrix translateMatrix; |
| 1025 std::tie(translateMatrix, translate) = untranslate(d); |
| 1026 SkDraw drawCopy(d); |
| 1027 drawCopy.fMatrix = &translateMatrix; |
| 1028 SkPath pathCopy(origPath); |
| 1029 pathCopy.offset(translate.x(), translate.y()); |
| 1030 this->drawPath(drawCopy, pathCopy, srcPaint, prePathMatrix, true); |
| 1031 return; // NOTE: shader behavior will be off. |
| 1032 } |
| 1033 |
| 984 SkPaint paint = srcPaint; | 1034 SkPaint paint = srcPaint; |
| 985 replace_srcmode_on_opaque_paint(&paint); | 1035 replace_srcmode_on_opaque_paint(&paint); |
| 986 SkPath modifiedPath; | 1036 SkPath modifiedPath; |
| 987 SkPath* pathPtr = const_cast<SkPath*>(&origPath); | 1037 SkPath* pathPtr = const_cast<SkPath*>(&origPath); |
| 988 | 1038 |
| 989 SkMatrix matrix = *d.fMatrix; | 1039 SkMatrix matrix = *d.fMatrix; |
| 990 if (prePathMatrix) { | 1040 if (prePathMatrix) { |
| 991 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { | 1041 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) { |
| 992 if (!pathIsMutable) { | 1042 if (!pathIsMutable) { |
| 993 pathPtr = &modifiedPath; | 1043 pathPtr = &modifiedPath; |
| (...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1266 device->drawText(d, text, len, x, y, transparent); | 1316 device->drawText(d, text, len, x, y, transparent); |
| 1267 break; | 1317 break; |
| 1268 default: | 1318 default: |
| 1269 SkFAIL("unknown text encoding"); | 1319 SkFAIL("unknown text encoding"); |
| 1270 } | 1320 } |
| 1271 } | 1321 } |
| 1272 | 1322 |
| 1273 | 1323 |
| 1274 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, | 1324 void SkPDFDevice::drawText(const SkDraw& d, const void* text, size_t len, |
| 1275 SkScalar x, SkScalar y, const SkPaint& srcPaint) { | 1325 SkScalar x, SkScalar y, const SkPaint& srcPaint) { |
| 1326 if (excessive_translation(*d.fMatrix)) { |
| 1327 SkVector translate; SkMatrix translateMatrix; |
| 1328 std::tie(translateMatrix, translate) = untranslate(d); |
| 1329 SkDraw drawCopy(d); |
| 1330 drawCopy.fMatrix = &translateMatrix; |
| 1331 this->drawText(drawCopy, text, len, x + translate.x(), |
| 1332 y + translate.y(), srcPaint); |
| 1333 return; // NOTE: shader behavior will be off. |
| 1334 } |
| 1335 |
| 1276 if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fCanon)) { | 1336 if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fCanon)) { |
| 1277 // https://bug.skia.org/3866 | 1337 // https://bug.skia.org/3866 |
| 1278 SkPath path; | 1338 SkPath path; |
| 1279 srcPaint.getTextPath(text, len, x, y, &path); | 1339 srcPaint.getTextPath(text, len, x, y, &path); |
| 1280 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); | 1340 this->drawPath(d, path, srcPaint, &SkMatrix::I(), true); |
| 1281 // Draw text transparently to make it copyable/searchable/accessable. | 1341 // Draw text transparently to make it copyable/searchable/accessable. |
| 1282 draw_transparent_text(this, d, text, len, x, y, srcPaint); | 1342 draw_transparent_text(this, d, text, len, x, y, srcPaint); |
| 1283 return; | 1343 return; |
| 1284 } | 1344 } |
| 1285 SkPaint paint = srcPaint; | 1345 SkPaint paint = srcPaint; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1327 content.entry()->fContent.writeText(encodedString.c_str()); | 1387 content.entry()->fContent.writeText(encodedString.c_str()); |
| 1328 consumedGlyphCount += availableGlyphs; | 1388 consumedGlyphCount += availableGlyphs; |
| 1329 content.entry()->fContent.writeText(" Tj\n"); | 1389 content.entry()->fContent.writeText(" Tj\n"); |
| 1330 } | 1390 } |
| 1331 content.entry()->fContent.writeText("ET\n"); | 1391 content.entry()->fContent.writeText("ET\n"); |
| 1332 } | 1392 } |
| 1333 | 1393 |
| 1334 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, | 1394 void SkPDFDevice::drawPosText(const SkDraw& d, const void* text, size_t len, |
| 1335 const SkScalar pos[], int scalarsPerPos, | 1395 const SkScalar pos[], int scalarsPerPos, |
| 1336 const SkPoint& offset, const SkPaint& srcPaint) { | 1396 const SkPoint& offset, const SkPaint& srcPaint) { |
| 1397 if (excessive_translation(*d.fMatrix)) { |
| 1398 SkVector translate; SkMatrix translateMatrix; |
| 1399 std::tie(translateMatrix, translate) = untranslate(d); |
| 1400 SkDraw drawCopy(d); |
| 1401 drawCopy.fMatrix = &translateMatrix; |
| 1402 SkPoint offsetCopy = offset; |
| 1403 SkPoint::Offset(&offsetCopy, 1, translate.x(), translate.y()); |
| 1404 this->drawPosText(drawCopy, text, len, pos, scalarsPerPos, offsetCopy, |
| 1405 srcPaint); |
| 1406 return; // NOTE: shader behavior will be off. |
| 1407 } |
| 1408 |
| 1337 if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fCanon)) { | 1409 if (!SkPDFFont::CanEmbedTypeface(srcPaint.getTypeface(), fCanon)) { |
| 1338 const SkPoint* positions = reinterpret_cast<const SkPoint*>(pos); | 1410 const SkPoint* positions = reinterpret_cast<const SkPoint*>(pos); |
| 1339 SkAutoTMalloc<SkPoint> positionsBuffer; | 1411 SkAutoTMalloc<SkPoint> positionsBuffer; |
| 1340 if (2 != scalarsPerPos) { | 1412 if (2 != scalarsPerPos) { |
| 1341 int glyphCount = srcPaint.textToGlyphs(text, len, NULL); | 1413 int glyphCount = srcPaint.textToGlyphs(text, len, NULL); |
| 1342 positionsBuffer.reset(glyphCount); | 1414 positionsBuffer.reset(glyphCount); |
| 1343 for (int i = 0; i < glyphCount; ++i) { | 1415 for (int i = 0; i < glyphCount; ++i) { |
| 1344 positionsBuffer[i].set(pos[i], 0.0f); | 1416 positionsBuffer[i].set(pos[i], 0.0f); |
| 1345 } | 1417 } |
| 1346 positions = &positionsBuffer[0]; | 1418 positions = &positionsBuffer[0]; |
| (...skipping 1016 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2363 if (!pdfimage) { | 2435 if (!pdfimage) { |
| 2364 pdfimage.reset(SkPDFCreateBitmapObject(image)); | 2436 pdfimage.reset(SkPDFCreateBitmapObject(image)); |
| 2365 if (!pdfimage) { | 2437 if (!pdfimage) { |
| 2366 return; | 2438 return; |
| 2367 } | 2439 } |
| 2368 fCanon->addPDFBitmap(image->uniqueID(), pdfimage); | 2440 fCanon->addPDFBitmap(image->uniqueID(), pdfimage); |
| 2369 } | 2441 } |
| 2370 SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), | 2442 SkPDFUtils::DrawFormXObject(this->addXObjectResource(pdfimage.get()), |
| 2371 &content.entry()->fContent); | 2443 &content.entry()->fContent); |
| 2372 } | 2444 } |
| OLD | NEW |