From ea9da8ded3e92b5725564bcab64fedaecb8c44f9 Mon Sep 17 00:00:00 2001 From: "vandebo@chromium.org" Date: Fri, 4 Mar 2011 03:15:13 +0000 Subject: [PDF] Restrict scalars to the range that PDF understands. * Add a config flag to ignore the restrictions * Apply restriction to both SkPDFScalar and scalars used in content streams. * +/- 32,767 for the integer part. * +/1 1/65536 for the fraction part. Review URL: http://codereview.appspot.com/4240050 git-svn-id: http://skia.googlecode.com/svn/trunk/src@882 2bbb7eff-a529-9590-31e7-b0007b416f81 --- pdf/SkPDFDevice.cpp | 52 +++++++++++++++++++++--------------------- pdf/SkPDFTypes.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 27 deletions(-) (limited to 'pdf') diff --git a/pdf/SkPDFDevice.cpp b/pdf/SkPDFDevice.cpp index d0f32ac3..ff9e4db4 100644 --- a/pdf/SkPDFDevice.cpp +++ b/pdf/SkPDFDevice.cpp @@ -48,14 +48,14 @@ SkString toPDFColor(SkColor color) { SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere. SkScalar colorMax = SkIntToScalar(0xFF); SkString result; - result.appendScalar(SkScalarDiv(SkIntToScalar(SkColorGetR(color)), - colorMax)); + SkPDFScalar::Append( + SkScalarDiv(SkIntToScalar(SkColorGetR(color)), colorMax), &result); result.append(" "); - result.appendScalar(SkScalarDiv(SkIntToScalar(SkColorGetG(color)), - colorMax)); + SkPDFScalar::Append( + SkScalarDiv(SkIntToScalar(SkColorGetG(color)), colorMax), &result); result.append(" "); - result.appendScalar(SkScalarDiv(SkIntToScalar(SkColorGetB(color)), - colorMax)); + SkPDFScalar::Append( + SkScalarDiv(SkIntToScalar(SkColorGetB(color)), colorMax), &result); result.append(" "); return result; } @@ -610,7 +610,7 @@ void SkPDFDevice::updateGSFromPaint(const SkPaint& newPaint, bool forText) { newPaint.getTextScaleX()) { SkScalar scale = newPaint.getTextScaleX(); SkScalar pdfScale = SkScalarMul(scale, SkIntToScalar(100)); - fContent.appendScalar(pdfScale); + SkPDFScalar::Append(pdfScale, &fContent); fContent.append(" Tz\n"); fGraphicStack[fGraphicStackIndex].fTextScaleX = scale; } @@ -639,7 +639,7 @@ void SkPDFDevice::updateFont(const SkPaint& paint, uint16_t glyphID) { fContent.append("/F"); fContent.appendS32(fontIndex); fContent.append(" "); - fContent.appendScalar(paint.getTextSize()); + SkPDFScalar::Append(paint.getTextSize(), &fContent); fContent.append(" Tf\n"); fGraphicStack[fGraphicStackIndex].fTextSize = paint.getTextSize(); fGraphicStack[fGraphicStackIndex].fFont = fFontResources[fontIndex]; @@ -660,16 +660,16 @@ int SkPDFDevice::getFontResourceIndex(uint32_t fontID, uint16_t glyphID) { } void SkPDFDevice::moveTo(SkScalar x, SkScalar y) { - fContent.appendScalar(x); + SkPDFScalar::Append(x, &fContent); fContent.append(" "); - fContent.appendScalar(y); + SkPDFScalar::Append(y, &fContent); fContent.append(" m\n"); } void SkPDFDevice::appendLine(SkScalar x, SkScalar y) { - fContent.appendScalar(x); + SkPDFScalar::Append(x, &fContent); fContent.append(" "); - fContent.appendScalar(y); + SkPDFScalar::Append(y, &fContent); fContent.append(" l\n"); } @@ -677,33 +677,33 @@ void SkPDFDevice::appendCubic(SkScalar ctl1X, SkScalar ctl1Y, SkScalar ctl2X, SkScalar ctl2Y, SkScalar dstX, SkScalar dstY) { SkString cmd("y\n"); - fContent.appendScalar(ctl1X); + SkPDFScalar::Append(ctl1X, &fContent); fContent.append(" "); - fContent.appendScalar(ctl1Y); + SkPDFScalar::Append(ctl1Y, &fContent); fContent.append(" "); if (ctl2X != dstX || ctl2Y != dstY) { cmd.set("c\n"); - fContent.appendScalar(ctl2X); + SkPDFScalar::Append(ctl2X, &fContent); fContent.append(" "); - fContent.appendScalar(ctl2Y); + SkPDFScalar::Append(ctl2Y, &fContent); fContent.append(" "); } - fContent.appendScalar(dstX); + SkPDFScalar::Append(dstX, &fContent); fContent.append(" "); - fContent.appendScalar(dstY); + SkPDFScalar::Append(dstY, &fContent); fContent.append(" "); fContent.append(cmd); } void SkPDFDevice::appendRectangle(SkScalar x, SkScalar y, SkScalar w, SkScalar h) { - fContent.appendScalar(x); + SkPDFScalar::Append(x, &fContent); fContent.append(" "); - fContent.appendScalar(y); + SkPDFScalar::Append(y, &fContent); fContent.append(" "); - fContent.appendScalar(w); + SkPDFScalar::Append(w, &fContent); fContent.append(" "); - fContent.appendScalar(h); + SkPDFScalar::Append(h, &fContent); fContent.append(" re\n"); } @@ -791,11 +791,11 @@ void SkPDFDevice::setTextTransform(SkScalar x, SkScalar y, SkScalar textSkewX) { // Flip the text about the x-axis to account for origin swap and include // the passed parameters. fContent.append("1 0 "); - fContent.appendScalar(0 - textSkewX); + SkPDFScalar::Append(0 - textSkewX, &fContent); fContent.append(" -1 "); - fContent.appendScalar(x); + SkPDFScalar::Append(x, &fContent); fContent.append(" "); - fContent.appendScalar(y); + SkPDFScalar::Append(y, &fContent); fContent.append(" Tm\n"); } @@ -851,7 +851,7 @@ SkMatrix SkPDFDevice::setTransform(const SkMatrix& m) { SkScalar transform[6]; SkAssertResult(m.pdfTransform(transform)); for (size_t i = 0; i < SK_ARRAY_COUNT(transform); i++) { - fContent.appendScalar(transform[i]); + SkPDFScalar::Append(transform[i], &fContent); fContent.append(" "); } fContent.append("cm\n"); diff --git a/pdf/SkPDFTypes.cpp b/pdf/SkPDFTypes.cpp index 209a2cf5..bbeeeeb8 100644 --- a/pdf/SkPDFTypes.cpp +++ b/pdf/SkPDFTypes.cpp @@ -18,6 +18,12 @@ #include "SkPDFTypes.h" #include "SkStream.h" +#ifdef SK_BUILD_FOR_WIN + #define SNPRINTF _snprintf +#else + #define SNPRINTF snprintf +#endif + SkPDFObject::SkPDFObject() {} SkPDFObject::~SkPDFObject() {} @@ -93,7 +99,64 @@ void SkPDFScalar::emitObject(SkWStream* stream, SkPDFCatalog* catalog, bool indirect) { if (indirect) return emitIndirectObject(stream, catalog); - stream->writeScalarAsText(fValue); + + SkString tmp; + Append(fValue, &tmp); + stream->write(tmp.c_str(), tmp.size()); +} + +// static +void SkPDFScalar::Append(SkScalar value, SkString* string) { + // The range of reals in PDF/A is the same as SkFixed: +/- 32,767 and + // +/- 1/65,536 (though integers can range from 2^31 - 1 to -2^31). + // When using floats that are outside the whole value range, we can use + // integers instead. + +#if defined(SK_SCALAR_IS_FIXED) + string->appendScalar(value); + return; +#endif // SK_SCALAR_IS_FIXED + +#if !defined(SK_ALLOW_LARGE_PDF_SCALARS) + if (value > 32767 || value < -32767) { + string->appendS32(SkScalarRound(value)); + return; + } + + char buffer[SkStrAppendScalar_MaxSize]; + char* end = SkStrAppendFixed(buffer, SkScalarToFixed(value)); + string->append(buffer, end - buffer); + return; +#endif // !SK_ALLOW_LARGE_PDF_SCALARS + +#if defined(SK_SCALAR_IS_FLOAT) && defined(SK_ALLOW_LARGE_PDF_SCALARS) + // Floats have 24bits of significance, so anything outside that range is + // no more precise than an int. (Plus PDF doesn't support scientific + // notation, so this clamps to SK_Max/MinS32). + if (value > (1 << 24) || value < -(1 << 24)) { + string->appendS32(value); + return; + } + // Continue to enforce the PDF limits for small floats. + if (value < 1.0f/65536 && value > -1.0f/65536) { + string->appendS32(0); + return; + } + // SkStrAppendFloat might still use scientific notation, so use snprintf + // directly.. + static const int kFloat_MaxSize = 19; + char buffer[kFloat_MaxSize]; + int len = SNPRINTF(buffer, kFloat_MaxSize, "%#.8f", value); + // %f always prints trailing 0s, so strip them. + for (; buffer[len - 1] == '0' && len > 0; len--) { + buffer[len - 1] = '\0'; + } + if (buffer[len - 1] == '.') { + buffer[len - 1] = '\0'; + } + string->append(buffer); + return; +#endif // SK_SCALAR_IS_FLOAT && SK_ALLOW_LARGE_PDF_SCALARS } SkPDFString::SkPDFString(const char value[]) -- cgit v1.2.3