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 |