Chromium Code Reviews| 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 |