 Chromium Code Reviews
 Chromium Code Reviews Issue 1438503002:
  SkPDF: fix large-number bug  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master
    
  
    Issue 1438503002:
  SkPDF: fix large-number bug  (Closed) 
  Base URL: https://skia.googlesource.com/skia.git@master| 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 |