зеркало из https://github.com/mozilla/moz-skia.git
[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@882 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
Родитель
e280f1d164
Коммит
094316bd28
|
@ -123,6 +123,11 @@
|
|||
*/
|
||||
//#define SK_ZLIB_INCLUDE <zlib.h>
|
||||
|
||||
/* Define this to allow PDF scalars above 32k. The PDF/A spec doesn't allow
|
||||
them, but modern PDF interpreters should handle them just fine.
|
||||
*/
|
||||
//#define SK_ALLOW_LARGE_PDF_SCALARS
|
||||
|
||||
/* Define this to remove dimension checks on bitmaps. Not all blits will be
|
||||
correct yet, so this is mostly for debugging the implementation.
|
||||
*/
|
||||
|
|
|
@ -151,6 +151,8 @@ public:
|
|||
explicit SkPDFScalar(SkScalar value);
|
||||
virtual ~SkPDFScalar();
|
||||
|
||||
static void Append(SkScalar value, SkString* string);
|
||||
|
||||
// The SkPDFObject interface.
|
||||
virtual void emitObject(SkWStream* stream, SkPDFCatalog* catalog,
|
||||
bool indirect);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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[])
|
||||
|
|
|
@ -122,6 +122,24 @@ static void TestPDFPrimitives(skiatest::Reporter* reporter) {
|
|||
realHalf->unref(); // SkRefPtr and new both took a reference.
|
||||
CheckObjectOutput(reporter, realHalf.get(), "0.5", true);
|
||||
|
||||
SkRefPtr<SkPDFScalar> bigScalar = new SkPDFScalar(110999.75);
|
||||
bigScalar->unref(); // SkRefPtr and new both took a reference.
|
||||
#if defined(SK_SCALAR_IS_FIXED) || !defined(SK_ALLOW_LARGE_PDF_SCALARS)
|
||||
CheckObjectOutput(reporter, bigScalar.get(), "111000", true);
|
||||
#else
|
||||
CheckObjectOutput(reporter, bigScalar.get(), "110999.75", true);
|
||||
#endif
|
||||
|
||||
#if defined(SK_SCALAR_IS_FLOAT) && defined(SK_ALLOW_LARGE_PDF_SCALARS)
|
||||
SkRefPtr<SkPDFScalar> biggerScalar = new SkPDFScalar(50000000.1);
|
||||
biggerScalar->unref(); // SkRefPtr and new both took a reference.
|
||||
CheckObjectOutput(reporter, biggerScalar.get(), "50000000", true);
|
||||
|
||||
SkRefPtr<SkPDFScalar> smallestScalar = new SkPDFScalar(1.0/65536);
|
||||
smallestScalar->unref(); // SkRefPtr and new both took a reference.
|
||||
CheckObjectOutput(reporter, smallestScalar.get(), "0.00001526", true);
|
||||
#endif
|
||||
|
||||
SkRefPtr<SkPDFString> stringSimple = new SkPDFString("test ) string ( foo");
|
||||
stringSimple->unref(); // SkRefPtr and new both took a reference.
|
||||
CheckObjectOutput(reporter, stringSimple.get(), "(test \\) string \\( foo)",
|
||||
|
|
Загрузка…
Ссылка в новой задаче