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