aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--bench/PDFBench.cpp16
-rw-r--r--src/pdf/SkPDFDevice.cpp7
-rw-r--r--src/pdf/SkPDFShader.cpp55
-rw-r--r--src/pdf/SkPDFTypes.cpp14
-rw-r--r--src/pdf/SkPDFTypes.h4
-rw-r--r--src/pdf/SkPDFUtils.cpp24
-rw-r--r--src/pdf/SkPDFUtils.h9
-rw-r--r--tests/PDFPrimitivesTest.cpp13
8 files changed, 110 insertions, 32 deletions
diff --git a/bench/PDFBench.cpp b/bench/PDFBench.cpp
index 8f5d2db5b4..19f8e2f8cd 100644
--- a/bench/PDFBench.cpp
+++ b/bench/PDFBench.cpp
@@ -164,6 +164,21 @@ struct PDFScalarBench : public Benchmark {
}
};
+struct PDFColorComponentBench : public Benchmark {
+ bool isSuitableFor(Backend b) override {
+ return b == kNonRendering_Backend;
+ }
+ const char* onGetName() override { return "PDFColorComponent"; }
+ void onDraw(int loops, SkCanvas*) override {
+ char dst[5];
+ while (loops-- > 0) {
+ for (int i = 0; i < 256; ++i) {
+ (void)SkPDFUtils::ColorToDecimal(SkToU8(i), dst);
+ }
+ }
+ }
+};
+
struct PDFShaderBench : public Benchmark {
sk_sp<SkShader> fShader;
const char* onGetName() final { return "PDFShader"; }
@@ -232,6 +247,7 @@ DEF_BENCH(return new PDFImageBench;)
DEF_BENCH(return new PDFJpegImageBench;)
DEF_BENCH(return new PDFCompressionBench;)
DEF_BENCH(return new PDFScalarBench;)
+DEF_BENCH(return new PDFColorComponentBench;)
DEF_BENCH(return new PDFShaderBench;)
DEF_BENCH(return new WStreamWriteTextBenchmark;)
DEF_BENCH(return new WritePDFTextBenchmark;)
diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp
index 8e76c442be..973ebea314 100644
--- a/src/pdf/SkPDFDevice.cpp
+++ b/src/pdf/SkPDFDevice.cpp
@@ -51,12 +51,11 @@ static void replace_srcmode_on_opaque_paint(SkPaint* paint) {
static void emit_pdf_color(SkColor color, SkWStream* result) {
SkASSERT(SkColorGetA(color) == 0xFF); // We handle alpha elsewhere.
- SkScalar colorScale = SkScalarInvert(0xFF);
- SkPDFUtils::AppendScalar(SkColorGetR(color) * colorScale, result);
+ SkPDFUtils::AppendColorComponent(SkColorGetR(color), result);
result->writeText(" ");
- SkPDFUtils::AppendScalar(SkColorGetG(color) * colorScale, result);
+ SkPDFUtils::AppendColorComponent(SkColorGetG(color), result);
result->writeText(" ");
- SkPDFUtils::AppendScalar(SkColorGetB(color) * colorScale, result);
+ SkPDFUtils::AppendColorComponent(SkColorGetB(color), result);
result->writeText(" ");
}
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index 942fe65d26..37df296280 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -40,6 +40,9 @@ static void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) {
matrix->postTranslate(pts[0].fX, pts[0].fY);
}
+static const int kColorComponents = 3;
+typedef uint8_t ColorTuple[kColorComponents];
+
/* Assumes t + startOffset is on the stack and does a linear interpolation on t
between startOffset and endOffset from prevColor to curColor (for each color
component), leaving the result in component order on the stack. It assumes
@@ -49,16 +52,16 @@ static void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) {
@param prevColor[components] The previous color components.
@param result The result ps function.
*/
-static void interpolateColorCode(SkScalar range, SkScalar* curColor,
- SkScalar* prevColor,
+static void interpolateColorCode(SkScalar range, const ColorTuple& curColor,
+ const ColorTuple& prevColor,
SkDynamicMemoryWStream* result) {
SkASSERT(range != SkIntToScalar(0));
- static const int kColorComponents = 3;
// Figure out how to scale each color component.
SkScalar multiplier[kColorComponents];
for (int i = 0; i < kColorComponents; i++) {
- multiplier[i] = (curColor[i] - prevColor[i]) / range;
+ static const SkScalar kColorScale = SkScalarInvert(255);
+ multiplier[i] = kColorScale * (curColor[i] - prevColor[i]) / range;
}
// Calculate when we no longer need to keep a copy of the input parameter t.
@@ -82,7 +85,7 @@ static void interpolateColorCode(SkScalar range, SkScalar* curColor,
}
if (multiplier[i] == 0) {
- SkPDFUtils::AppendScalar(prevColor[i], result);
+ SkPDFUtils::AppendColorComponent(prevColor[i], result);
result->writeText(" ");
} else {
if (multiplier[i] != 1) {
@@ -90,7 +93,7 @@ static void interpolateColorCode(SkScalar range, SkScalar* curColor,
result->writeText(" mul ");
}
if (prevColor[i] != 0) {
- SkPDFUtils::AppendScalar(prevColor[i], result);
+ SkPDFUtils::AppendColorComponent(prevColor[i], result);
result->writeText(" add ");
}
}
@@ -122,8 +125,6 @@ static void interpolateColorCode(SkScalar range, SkScalar* curColor,
}
}
*/
-static const int kColorComponents = 3;
-typedef SkScalar ColorTuple[kColorComponents];
static void gradientFunctionCode(const SkShader::GradientInfo& info,
SkDynamicMemoryWStream* result) {
/* We want to linearly interpolate from the previous color to the next.
@@ -134,20 +135,19 @@ static void gradientFunctionCode(const SkShader::GradientInfo& info,
SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount);
ColorTuple *colorData = colorDataAlloc.get();
- const SkScalar scale = SkScalarInvert(SkIntToScalar(255));
for (int i = 0; i < info.fColorCount; i++) {
- colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale);
- colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale);
- colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale);
+ colorData[i][0] = SkColorGetR(info.fColors[i]);
+ colorData[i][1] = SkColorGetG(info.fColors[i]);
+ colorData[i][2] = SkColorGetB(info.fColors[i]);
}
// Clamp the initial color.
result->writeText("dup 0 le {pop ");
- SkPDFUtils::AppendScalar(colorData[0][0], result);
+ SkPDFUtils::AppendColorComponent(colorData[0][0], result);
result->writeText(" ");
- SkPDFUtils::AppendScalar(colorData[0][1], result);
+ SkPDFUtils::AppendColorComponent(colorData[0][1], result);
result->writeText(" ");
- SkPDFUtils::AppendScalar(colorData[0][2], result);
+ SkPDFUtils::AppendColorComponent(colorData[0][2], result);
result->writeText(" }\n");
// The gradient colors.
@@ -173,11 +173,11 @@ static void gradientFunctionCode(const SkShader::GradientInfo& info,
// Clamp the final color.
result->writeText("{pop ");
- SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][0], result);
+ SkPDFUtils::AppendColorComponent(colorData[info.fColorCount - 1][0], result);
result->writeText(" ");
- SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][1], result);
+ SkPDFUtils::AppendColorComponent(colorData[info.fColorCount - 1][1], result);
result->writeText(" ");
- SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][2], result);
+ SkPDFUtils::AppendColorComponent(colorData[info.fColorCount - 1][2], result);
for (int i = 0 ; i < gradients + 1; i++) {
result->writeText("} ifelse\n");
@@ -189,15 +189,15 @@ static sk_sp<SkPDFDict> createInterpolationFunction(const ColorTuple& color1,
auto retval = sk_make_sp<SkPDFDict>();
auto c0 = sk_make_sp<SkPDFArray>();
- c0->appendScalar(color1[0]);
- c0->appendScalar(color1[1]);
- c0->appendScalar(color1[2]);
+ c0->appendColorComponent(color1[0]);
+ c0->appendColorComponent(color1[1]);
+ c0->appendColorComponent(color1[2]);
retval->insertObject("C0", std::move(c0));
auto c1 = sk_make_sp<SkPDFArray>();
- c1->appendScalar(color2[0]);
- c1->appendScalar(color2[1]);
- c1->appendScalar(color2[2]);
+ c1->appendColorComponent(color2[0]);
+ c1->appendColorComponent(color2[1]);
+ c1->appendColorComponent(color2[2]);
retval->insertObject("C1", std::move(c1));
auto domain = sk_make_sp<SkPDFArray>();
@@ -248,11 +248,10 @@ static sk_sp<SkPDFDict> gradientStitchCode(const SkShader::GradientInfo& info) {
SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(colorCount);
ColorTuple *colorData = colorDataAlloc.get();
- const SkScalar scale = SkScalarInvert(SkIntToScalar(255));
for (int i = 0; i < colorCount; i++) {
- colorData[i][0] = SkScalarMul(SkColorGetR(colors[i]), scale);
- colorData[i][1] = SkScalarMul(SkColorGetG(colors[i]), scale);
- colorData[i][2] = SkScalarMul(SkColorGetB(colors[i]), scale);
+ colorData[i][0] = SkColorGetR(colors[i]);
+ colorData[i][1] = SkColorGetG(colors[i]);
+ colorData[i][2] = SkColorGetB(colors[i]);
}
// no need for a stitch function if there are only 2 stops.
diff --git a/src/pdf/SkPDFTypes.cpp b/src/pdf/SkPDFTypes.cpp
index f9ab5e492a..8c59a4a008 100644
--- a/src/pdf/SkPDFTypes.cpp
+++ b/src/pdf/SkPDFTypes.cpp
@@ -118,6 +118,9 @@ void SkPDFUnion::emitObject(SkWStream* stream,
case Type::kInt:
stream->writeDecAsText(fIntValue);
return;
+ case Type::kColorComponent:
+ SkPDFUtils::AppendColorComponent(SkToU8(fIntValue), stream);
+ return;
case Type::kBool:
stream->writeText(fBoolValue ? "true" : "false");
return;
@@ -159,6 +162,7 @@ void SkPDFUnion::addResources(SkPDFObjNumMap* objNumMap,
const SkPDFSubstituteMap& substituteMap) const {
switch (fType) {
case Type::kInt:
+ case Type::kColorComponent:
case Type::kBool:
case Type::kScalar:
case Type::kName:
@@ -185,6 +189,12 @@ SkPDFUnion SkPDFUnion::Int(int32_t value) {
return u;
}
+SkPDFUnion SkPDFUnion::ColorComponent(uint8_t value) {
+ SkPDFUnion u(Type::kColorComponent);
+ u.fIntValue = value;
+ return u;
+}
+
SkPDFUnion SkPDFUnion::Bool(bool value) {
SkPDFUnion u(Type::kBool);
u.fBoolValue = value;
@@ -300,6 +310,10 @@ void SkPDFArray::appendInt(int32_t value) {
this->append(SkPDFUnion::Int(value));
}
+void SkPDFArray::appendColorComponent(uint8_t value) {
+ this->append(SkPDFUnion::ColorComponent(value));
+}
+
void SkPDFArray::appendBool(bool value) {
this->append(SkPDFUnion::Bool(value));
}
diff --git a/src/pdf/SkPDFTypes.h b/src/pdf/SkPDFTypes.h
index cff60e539a..5e4de3a259 100644
--- a/src/pdf/SkPDFTypes.h
+++ b/src/pdf/SkPDFTypes.h
@@ -90,6 +90,8 @@ public:
static SkPDFUnion Scalar(SkScalar);
+ static SkPDFUnion ColorComponent(uint8_t);
+
/** These two functions do NOT take ownership of char*, and do NOT
copy the string. Suitable for passing in static const
strings. For example:
@@ -139,6 +141,7 @@ private:
kDestroyed object. */
kDestroyed = 0,
kInt,
+ kColorComponent,
kBool,
kScalar,
kName,
@@ -212,6 +215,7 @@ public:
* @param value The value to add to the array.
*/
void appendInt(int32_t);
+ void appendColorComponent(uint8_t);
void appendBool(bool);
void appendScalar(SkScalar);
void appendName(const char[]);
diff --git a/src/pdf/SkPDFUtils.cpp b/src/pdf/SkPDFUtils.cpp
index b8d65092b0..9e4ac515ba 100644
--- a/src/pdf/SkPDFUtils.cpp
+++ b/src/pdf/SkPDFUtils.cpp
@@ -7,6 +7,7 @@
#include "SkData.h"
+#include "SkFixed.h"
#include "SkGeometry.h"
#include "SkPDFResourceDict.h"
#include "SkPDFUtils.h"
@@ -251,6 +252,29 @@ void SkPDFUtils::ApplyPattern(int objectIndex, SkWStream* content) {
content->writeText(" scn\n");
}
+size_t SkPDFUtils::ColorToDecimal(uint8_t value, char result[5]) {
+ if (value == 255 || value == 0) {
+ result[0] = value ? '1' : '0';
+ result[1] = '\0';
+ return 1;
+ }
+ // int x = 0.5 + (1000.0 / 255.0) * value;
+ int x = SkFixedRoundToInt((SK_Fixed1 * 1000 / 255) * value);
+ result[0] = '.';
+ for (int i = 3; i > 0; --i) {
+ result[i] = '0' + x % 10;
+ x /= 10;
+ }
+ int j;
+ for (j = 3; j > 1; --j) {
+ if (result[j] != '0') {
+ break;
+ }
+ }
+ result[j + 1] = '\0';
+ return j + 1;
+}
+
void SkPDFUtils::AppendScalar(SkScalar value, SkWStream* stream) {
char result[kMaximumFloatDecimalLength];
size_t len = SkPDFUtils::FloatToDecimal(SkScalarToFloat(value), result);
diff --git a/src/pdf/SkPDFUtils.h b/src/pdf/SkPDFUtils.h
index 3ddd3d0933..a9194f2e72 100644
--- a/src/pdf/SkPDFUtils.h
+++ b/src/pdf/SkPDFUtils.h
@@ -57,6 +57,15 @@ void DrawFormXObject(int objectIndex, SkWStream* content);
void ApplyGraphicState(int objectIndex, SkWStream* content);
void ApplyPattern(int objectIndex, SkWStream* content);
+// Converts (value / 255.0) with three significant digits of accuracy.
+// Writes value as string into result. Returns strlen() of result.
+size_t ColorToDecimal(uint8_t value, char result[5]);
+inline void AppendColorComponent(uint8_t value, SkWStream* wStream) {
+ char buffer[5];
+ size_t len = SkPDFUtils::ColorToDecimal(value, buffer);
+ wStream->write(buffer, len);
+}
+
// 3 = '-', '.', and '\0' characters.
// 9 = number of significant digits
// abs(FLT_MIN_10_EXP) = number of zeros in FLT_MIN
diff --git a/tests/PDFPrimitivesTest.cpp b/tests/PDFPrimitivesTest.cpp
index 9e2a89e609..d816b60823 100644
--- a/tests/PDFPrimitivesTest.cpp
+++ b/tests/PDFPrimitivesTest.cpp
@@ -491,3 +491,16 @@ DEF_TEST(PDFPrimitives_Scalar, reporter) {
check_pdf_scalar_serialization(reporter, inputFloat);
}
}
+
+// Test SkPDFUtils:: for accuracy.
+DEF_TEST(PDFPrimitives_Color, reporter) {
+ char buffer[5];
+ for (int i = 0; i < 256; ++i) {
+ size_t len = SkPDFUtils::ColorToDecimal(i, buffer);
+ REPORTER_ASSERT(reporter, len == strlen(buffer));
+ float f;
+ REPORTER_ASSERT(reporter, 1 == sscanf(buffer, "%f", &f));
+ int roundTrip = (int)(0.5 + f * 255);
+ REPORTER_ASSERT(reporter, roundTrip == i);
+ }
+}