aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pdf/SkPDFShader.cpp
diff options
context:
space:
mode:
authorGravatar halcanary <halcanary@google.com>2016-03-25 05:52:57 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-03-25 05:52:57 -0700
commitd11c7268a2a4303e842f4ba16da98fcd0a2b7555 (patch)
tree80a929bff0e3ded16db8625c6f62aa92160ab1f4 /src/pdf/SkPDFShader.cpp
parent2e59f1f2fd497367585374eb20f5c04d92ae6d26 (diff)
SkPDF: speed up SkPDFShader generation.
Stop using SkString::append() when SkDynamicMemoryWStream works better. Also add a bench to prove that this speeds things up: before: micros bench 59.33 ? PDFShader nonrendering after: micros bench 34.55 ? PDFShader nonrendering GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1833793002 Review URL: https://codereview.chromium.org/1833793002
Diffstat (limited to 'src/pdf/SkPDFShader.cpp')
-rw-r--r--src/pdf/SkPDFShader.cpp306
1 files changed, 154 insertions, 152 deletions
diff --git a/src/pdf/SkPDFShader.cpp b/src/pdf/SkPDFShader.cpp
index a9f2754226..7fb1f899f1 100644
--- a/src/pdf/SkPDFShader.cpp
+++ b/src/pdf/SkPDFShader.cpp
@@ -51,7 +51,8 @@ static void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) {
@param result The result ps function.
*/
static void interpolateColorCode(SkScalar range, SkScalar* curColor,
- SkScalar* prevColor, SkString* result) {
+ SkScalar* prevColor,
+ SkDynamicMemoryWStream* result) {
SkASSERT(range != SkIntToScalar(0));
static const int kColorComponents = 3;
@@ -71,32 +72,32 @@ static void interpolateColorCode(SkScalar range, SkScalar* curColor,
}
if (!dupInput[0] && multiplier[0] == 0) {
- result->append("pop ");
+ result->writeText("pop ");
}
for (int i = 0; i < kColorComponents; i++) {
// If the next components needs t and this component will consume a
// copy, make another copy.
if (dupInput[i] && multiplier[i] != 0) {
- result->append("dup ");
+ result->writeText("dup ");
}
if (multiplier[i] == 0) {
- result->appendScalar(prevColor[i]);
- result->append(" ");
+ SkPDFUtils::AppendScalar(prevColor[i], result);
+ result->writeText(" ");
} else {
if (multiplier[i] != 1) {
- result->appendScalar(multiplier[i]);
- result->append(" mul ");
+ SkPDFUtils::AppendScalar(multiplier[i], result);
+ result->writeText(" mul ");
}
if (prevColor[i] != 0) {
- result->appendScalar(prevColor[i]);
- result->append(" add ");
+ SkPDFUtils::AppendScalar(prevColor[i], result);
+ result->writeText(" add ");
}
}
if (dupInput[i]) {
- result->append("exch\n");
+ result->writeText("exch\n");
}
}
}
@@ -123,7 +124,7 @@ static void interpolateColorCode(SkScalar range, SkScalar* curColor,
}
*/
static void gradientFunctionCode(const SkShader::GradientInfo& info,
- SkString* result) {
+ SkDynamicMemoryWStream* result) {
/* We want to linearly interpolate from the previous color to the next.
Scale the colors from 0..255 to 0..1 and determine the multipliers
for interpolation.
@@ -141,13 +142,13 @@ static void gradientFunctionCode(const SkShader::GradientInfo& info,
}
// Clamp the initial color.
- result->append("dup 0 le {pop ");
- result->appendScalar(colorData[0][0]);
- result->append(" ");
- result->appendScalar(colorData[0][1]);
- result->append(" ");
- result->appendScalar(colorData[0][2]);
- result->append(" }\n");
+ result->writeText("dup 0 le {pop ");
+ SkPDFUtils::AppendScalar(colorData[0][0], result);
+ result->writeText(" ");
+ SkPDFUtils::AppendScalar(colorData[0][1], result);
+ result->writeText(" ");
+ SkPDFUtils::AppendScalar(colorData[0][2], result);
+ result->writeText(" }\n");
// The gradient colors.
int gradients = 0;
@@ -157,54 +158,55 @@ static void gradientFunctionCode(const SkShader::GradientInfo& info,
}
gradients++;
- result->append("{dup ");
- result->appendScalar(info.fColorOffsets[i]);
- result->append(" le {");
+ result->writeText("{dup ");
+ SkPDFUtils::AppendScalar(info.fColorOffsets[i], result);
+ result->writeText(" le {");
if (info.fColorOffsets[i - 1] != 0) {
- result->appendScalar(info.fColorOffsets[i - 1]);
- result->append(" sub\n");
+ SkPDFUtils::AppendScalar(info.fColorOffsets[i - 1], result);
+ result->writeText(" sub\n");
}
interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1],
colorData[i], colorData[i - 1], result);
- result->append("}\n");
+ result->writeText("}\n");
}
// Clamp the final color.
- result->append("{pop ");
- result->appendScalar(colorData[info.fColorCount - 1][0]);
- result->append(" ");
- result->appendScalar(colorData[info.fColorCount - 1][1]);
- result->append(" ");
- result->appendScalar(colorData[info.fColorCount - 1][2]);
+ result->writeText("{pop ");
+ SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][0], result);
+ result->writeText(" ");
+ SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][1], result);
+ result->writeText(" ");
+ SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][2], result);
for (int i = 0 ; i < gradients + 1; i++) {
- result->append("} ifelse\n");
+ result->writeText("} ifelse\n");
}
}
/* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */
-static void tileModeCode(SkShader::TileMode mode, SkString* result) {
+static void tileModeCode(SkShader::TileMode mode,
+ SkDynamicMemoryWStream* result) {
if (mode == SkShader::kRepeat_TileMode) {
- result->append("dup truncate sub\n"); // Get the fractional part.
- result->append("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1)
+ result->writeText("dup truncate sub\n"); // Get the fractional part.
+ result->writeText("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1)
return;
}
if (mode == SkShader::kMirror_TileMode) {
// Map t mod 2 into [0, 1, 1, 0].
// Code Stack
- result->append("abs " // Map negative to positive.
- "dup " // t.s t.s
- "truncate " // t.s t
- "dup " // t.s t t
- "cvi " // t.s t T
- "2 mod " // t.s t (i mod 2)
- "1 eq " // t.s t true|false
- "3 1 roll " // true|false t.s t
- "sub " // true|false 0.s
- "exch " // 0.s true|false
- "{1 exch sub} if\n"); // 1 - 0.s|0.s
+ result->writeText("abs " // Map negative to positive.
+ "dup " // t.s t.s
+ "truncate " // t.s t
+ "dup " // t.s t t
+ "cvi " // t.s t T
+ "2 mod " // t.s t (i mod 2)
+ "1 eq " // t.s t true|false
+ "3 1 roll " // true|false t.s t
+ "sub " // true|false 0.s
+ "exch " // 0.s true|false
+ "{1 exch sub} if\n"); // 1 - 0.s|0.s
}
}
@@ -217,11 +219,11 @@ static void tileModeCode(SkShader::TileMode mode, SkString* result) {
* while the rest of the stack is preserved intact.
* inversePerspectiveMatrix is the inverse perspective matrix.
*/
-static SkString apply_perspective_to_coordinates(
- const SkMatrix& inversePerspectiveMatrix) {
- SkString code;
+static void apply_perspective_to_coordinates(
+ const SkMatrix& inversePerspectiveMatrix,
+ SkDynamicMemoryWStream* code) {
if (!inversePerspectiveMatrix.hasPerspective()) {
- return code;
+ return;
}
// Perspective matrix should be:
@@ -237,46 +239,46 @@ static SkString apply_perspective_to_coordinates(
// x = x / (p2 + p0 x + p1 y)
// Input on stack: x y
- code.append(" dup "); // x y y
- code.appendScalar(p1); // x y y p1
- code.append(" mul " // x y y*p1
- " 2 index "); // x y y*p1 x
- code.appendScalar(p0); // x y y p1 x p0
- code.append(" mul "); // x y y*p1 x*p0
- code.appendScalar(p2); // x y y p1 x*p0 p2
- code.append(" add " // x y y*p1 x*p0+p2
- "add " // x y y*p1+x*p0+p2
- "3 1 roll " // y*p1+x*p0+p2 x y
- "2 index " // z x y y*p1+x*p0+p2
- "div " // y*p1+x*p0+p2 x y/(y*p1+x*p0+p2)
- "3 1 roll " // y/(y*p1+x*p0+p2) y*p1+x*p0+p2 x
- "exch " // y/(y*p1+x*p0+p2) x y*p1+x*p0+p2
- "div " // y/(y*p1+x*p0+p2) x/(y*p1+x*p0+p2)
- "exch\n"); // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2)
- return code;
+ code->writeText(" dup "); // x y y
+ SkPDFUtils::AppendScalar(p1, code); // x y y p1
+ code->writeText(" mul " // x y y*p1
+ " 2 index "); // x y y*p1 x
+ SkPDFUtils::AppendScalar(p0, code); // x y y p1 x p0
+ code->writeText(" mul "); // x y y*p1 x*p0
+ SkPDFUtils::AppendScalar(p2, code); // x y y p1 x*p0 p2
+ code->writeText(" add " // x y y*p1 x*p0+p2
+ "add " // x y y*p1+x*p0+p2
+ "3 1 roll " // y*p1+x*p0+p2 x y
+ "2 index " // z x y y*p1+x*p0+p2
+ "div " // y*p1+x*p0+p2 x y/(y*p1+x*p0+p2)
+ "3 1 roll " // y/(y*p1+x*p0+p2) y*p1+x*p0+p2 x
+ "exch " // y/(y*p1+x*p0+p2) x y*p1+x*p0+p2
+ "div " // y/(y*p1+x*p0+p2) x/(y*p1+x*p0+p2)
+ "exch\n"); // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2)
}
-static SkString linearCode(const SkShader::GradientInfo& info,
- const SkMatrix& perspectiveRemover) {
- SkString function("{");
+static void linearCode(const SkShader::GradientInfo& info,
+ const SkMatrix& perspectiveRemover,
+ SkDynamicMemoryWStream* function) {
+ function->writeText("{");
- function.append(apply_perspective_to_coordinates(perspectiveRemover));
+ apply_perspective_to_coordinates(perspectiveRemover, function);
- function.append("pop\n"); // Just ditch the y value.
- tileModeCode(info.fTileMode, &function);
- gradientFunctionCode(info, &function);
- function.append("}");
- return function;
+ function->writeText("pop\n"); // Just ditch the y value.
+ tileModeCode(info.fTileMode, function);
+ gradientFunctionCode(info, function);
+ function->writeText("}");
}
-static SkString radialCode(const SkShader::GradientInfo& info,
- const SkMatrix& perspectiveRemover) {
- SkString function("{");
+static void radialCode(const SkShader::GradientInfo& info,
+ const SkMatrix& perspectiveRemover,
+ SkDynamicMemoryWStream* function) {
+ function->writeText("{");
- function.append(apply_perspective_to_coordinates(perspectiveRemover));
+ apply_perspective_to_coordinates(perspectiveRemover, function);
// Find the distance from the origin.
- function.append("dup " // x y y
+ function->writeText("dup " // x y y
"mul " // x y^2
"exch " // y^2 x
"dup " // y^2 x x
@@ -284,17 +286,17 @@ static SkString radialCode(const SkShader::GradientInfo& info,
"add " // y^2+x^2
"sqrt\n"); // sqrt(y^2+x^2)
- tileModeCode(info.fTileMode, &function);
- gradientFunctionCode(info, &function);
- function.append("}");
- return function;
+ tileModeCode(info.fTileMode, function);
+ gradientFunctionCode(info, function);
+ function->writeText("}");
}
/* Conical gradient shader, based on the Canvas spec for radial gradients
See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient
*/
-static SkString twoPointConicalCode(const SkShader::GradientInfo& info,
- const SkMatrix& perspectiveRemover) {
+static void twoPointConicalCode(const SkShader::GradientInfo& info,
+ const SkMatrix& perspectiveRemover,
+ SkDynamicMemoryWStream* function) {
SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX;
SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY;
SkScalar r0 = info.fRadius[0];
@@ -307,24 +309,24 @@ static SkString twoPointConicalCode(const SkShader::GradientInfo& info,
// We start with a stack of (x y), copy it and then consume one copy in
// order to calculate b and the other to calculate c.
- SkString function("{");
+ function->writeText("{");
- function.append(apply_perspective_to_coordinates(perspectiveRemover));
+ apply_perspective_to_coordinates(perspectiveRemover, function);
- function.append("2 copy ");
+ function->writeText("2 copy ");
// Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr).
- function.appendScalar(dy);
- function.append(" mul exch ");
- function.appendScalar(dx);
- function.append(" mul add ");
- function.appendScalar(SkScalarMul(r0, dr));
- function.append(" add -2 mul dup dup mul\n");
+ SkPDFUtils::AppendScalar(dy, function);
+ function->writeText(" mul exch ");
+ SkPDFUtils::AppendScalar(dx, function);
+ function->writeText(" mul add ");
+ SkPDFUtils::AppendScalar(SkScalarMul(r0, dr), function);
+ function->writeText(" add -2 mul dup dup mul\n");
// c = x^2 + y^2 + radius0^2
- function.append("4 2 roll dup mul exch dup mul add ");
- function.appendScalar(SkScalarMul(r0, r0));
- function.append(" sub dup 4 1 roll\n");
+ function->writeText("4 2 roll dup mul exch dup mul add ");
+ SkPDFUtils::AppendScalar(SkScalarMul(r0, r0), function);
+ function->writeText(" sub dup 4 1 roll\n");
// Contents of the stack at this point: c, b, b^2, c
@@ -332,16 +334,16 @@ static SkString twoPointConicalCode(const SkShader::GradientInfo& info,
if (a == 0) {
// t = -c/b
- function.append("pop pop div neg dup ");
+ function->writeText("pop pop div neg dup ");
// compute radius(t)
- function.appendScalar(dr);
- function.append(" mul ");
- function.appendScalar(r0);
- function.append(" add\n");
+ SkPDFUtils::AppendScalar(dr, function);
+ function->writeText(" mul ");
+ SkPDFUtils::AppendScalar(r0, function);
+ function->writeText(" add\n");
// if r(t) < 0, then it's outside the cone
- function.append("0 lt {pop false} {true} ifelse\n");
+ function->writeText("0 lt {pop false} {true} ifelse\n");
} else {
@@ -349,70 +351,68 @@ static SkString twoPointConicalCode(const SkShader::GradientInfo& info,
// root t for which radius(t) > 0
// compute the discriminant (b^2 - 4ac)
- function.appendScalar(SkScalarMul(SkIntToScalar(4), a));
- function.append(" mul sub dup\n");
+ SkPDFUtils::AppendScalar(SkScalarMul(SkIntToScalar(4), a), function);
+ function->writeText(" mul sub dup\n");
// if d >= 0, proceed
- function.append("0 ge {\n");
+ function->writeText("0 ge {\n");
// an intermediate value we'll use to compute the roots:
// q = -0.5 * (b +/- sqrt(d))
- function.append("sqrt exch dup 0 lt {exch -1 mul} if");
- function.append(" add -0.5 mul dup\n");
+ function->writeText("sqrt exch dup 0 lt {exch -1 mul} if");
+ function->writeText(" add -0.5 mul dup\n");
// first root = q / a
- function.appendScalar(a);
- function.append(" div\n");
+ SkPDFUtils::AppendScalar(a, function);
+ function->writeText(" div\n");
// second root = c / q
- function.append("3 1 roll div\n");
+ function->writeText("3 1 roll div\n");
// put the larger root on top of the stack
- function.append("2 copy gt {exch} if\n");
+ function->writeText("2 copy gt {exch} if\n");
// compute radius(t) for larger root
- function.append("dup ");
- function.appendScalar(dr);
- function.append(" mul ");
- function.appendScalar(r0);
- function.append(" add\n");
+ function->writeText("dup ");
+ SkPDFUtils::AppendScalar(dr, function);
+ function->writeText(" mul ");
+ SkPDFUtils::AppendScalar(r0, function);
+ function->writeText(" add\n");
// if r(t) > 0, we have our t, pop off the smaller root and we're done
- function.append(" 0 gt {exch pop true}\n");
+ function->writeText(" 0 gt {exch pop true}\n");
// otherwise, throw out the larger one and try the smaller root
- function.append("{pop dup\n");
- function.appendScalar(dr);
- function.append(" mul ");
- function.appendScalar(r0);
- function.append(" add\n");
+ function->writeText("{pop dup\n");
+ SkPDFUtils::AppendScalar(dr, function);
+ function->writeText(" mul ");
+ SkPDFUtils::AppendScalar(r0, function);
+ function->writeText(" add\n");
// if r(t) < 0, push false, otherwise the smaller root is our t
- function.append("0 le {pop false} {true} ifelse\n");
- function.append("} ifelse\n");
+ function->writeText("0 le {pop false} {true} ifelse\n");
+ function->writeText("} ifelse\n");
// d < 0, clear the stack and push false
- function.append("} {pop pop pop false} ifelse\n");
+ function->writeText("} {pop pop pop false} ifelse\n");
}
// if the pixel is in the cone, proceed to compute a color
- function.append("{");
- tileModeCode(info.fTileMode, &function);
- gradientFunctionCode(info, &function);
+ function->writeText("{");
+ tileModeCode(info.fTileMode, function);
+ gradientFunctionCode(info, function);
// otherwise, just write black
- function.append("} {0 0 0} ifelse }");
-
- return function;
+ function->writeText("} {0 0 0} ifelse }");
}
-static SkString sweepCode(const SkShader::GradientInfo& info,
- const SkMatrix& perspectiveRemover) {
- SkString function("{exch atan 360 div\n");
- tileModeCode(info.fTileMode, &function);
- gradientFunctionCode(info, &function);
- function.append("}");
- return function;
+static void sweepCode(const SkShader::GradientInfo& info,
+ const SkMatrix& perspectiveRemover,
+ SkDynamicMemoryWStream* function) {
+ function->writeText("{exch atan 360 div\n");
+ tileModeCode(info.fTileMode, function);
+ gradientFunctionCode(info, function);
+ function->writeText("}");
}
static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& matrix) {
@@ -689,12 +689,11 @@ sk_sp<SkPDFArray> SkPDFShader::MakeRangeObject() {
return range;
}
-static sk_sp<SkPDFStream> make_ps_function(const SkString& psCode,
- SkPDFArray* domain,
- sk_sp<SkPDFObject> range) {
- SkAutoDataUnref funcData(
- SkData::NewWithCopy(psCode.c_str(), psCode.size()));
- auto result = sk_make_sp<SkPDFStream>(funcData.get());
+static sk_sp<SkPDFStream> make_ps_function(
+ std::unique_ptr<SkStreamAsset> psCode,
+ SkPDFArray* domain,
+ sk_sp<SkPDFObject> range) {
+ auto result = sk_make_sp<SkPDFStream>(psCode.get());
result->insertInt("FunctionType", 4);
result->insertObject("Domain", sk_ref_sp(domain));
result->insertObject("Range", std::move(range));
@@ -705,8 +704,9 @@ SkPDFFunctionShader* SkPDFFunctionShader::Create(
SkPDFCanon* canon, SkAutoTDelete<SkPDFShader::State>* autoState) {
const SkPDFShader::State& state = **autoState;
- SkString (*codeFunction)(const SkShader::GradientInfo& info,
- const SkMatrix& perspectiveRemover) = nullptr;
+ void (*codeFunction)(const SkShader::GradientInfo& info,
+ const SkMatrix& perspectiveRemover,
+ SkDynamicMemoryWStream* function) = nullptr;
SkPoint transformPoints[2];
// Depending on the type of the gradient, we want to transform the
@@ -777,7 +777,7 @@ SkPDFFunctionShader* SkPDFFunctionShader::Create(
domain->appendScalar(bbox.fTop);
domain->appendScalar(bbox.fBottom);
- SkString functionCode;
+ SkDynamicMemoryWStream functionCode;
// The two point radial gradient further references
// state.fInfo
// in translating from x, y coordinates to the t parameter. So, we have
@@ -793,9 +793,9 @@ SkPDFFunctionShader* SkPDFFunctionShader::Create(
inverseMapperMatrix.mapRadius(info->fRadius[0]);
twoPointRadialInfo.fRadius[1] =
inverseMapperMatrix.mapRadius(info->fRadius[1]);
- functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly);
+ codeFunction(twoPointRadialInfo, perspectiveInverseOnly, &functionCode);
} else {
- functionCode = codeFunction(*info, perspectiveInverseOnly);
+ codeFunction(*info, perspectiveInverseOnly, &functionCode);
}
auto pdfShader = sk_make_sp<SkPDFDict>();
@@ -806,7 +806,9 @@ SkPDFFunctionShader* SkPDFFunctionShader::Create(
// Call canon->makeRangeObject() instead of
// SkPDFShader::MakeRangeObject() so that the canon can
// deduplicate.
- auto function = make_ps_function(functionCode, domain.get(),
+ std::unique_ptr<SkStreamAsset> functionStream(
+ functionCode.detachAsStream());
+ auto function = make_ps_function(std::move(functionStream), domain.get(),
canon->makeRangeObject());
pdfShader->insertObjRef("Function", std::move(function));