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
This commit is contained in:
halcanary 2016-03-25 05:52:57 -07:00 committed by Commit bot
parent 2e59f1f2fd
commit d11c7268a2
3 changed files with 186 additions and 152 deletions

View File

@ -9,8 +9,11 @@
#include "Resources.h" #include "Resources.h"
#include "SkAutoPixmapStorage.h" #include "SkAutoPixmapStorage.h"
#include "SkData.h" #include "SkData.h"
#include "SkGradientShader.h"
#include "SkImage.h" #include "SkImage.h"
#include "SkPDFBitmap.h" #include "SkPDFBitmap.h"
#include "SkPDFDocument.h"
#include "SkPDFShader.h"
#include "SkPDFUtils.h" #include "SkPDFUtils.h"
#include "SkPixmap.h" #include "SkPixmap.h"
#include "SkRandom.h" #include "SkRandom.h"
@ -162,8 +165,36 @@ struct PDFScalarBench : public Benchmark {
} }
}; };
struct PDFShaderBench : public Benchmark {
sk_sp<SkShader> fShader;
const char* onGetName() final { return "PDFShader"; }
bool isSuitableFor(Backend b) final { return b == kNonRendering_Backend; }
void onDelayedSetup() final {
const SkPoint pts[2] = {{0.0f, 0.0f}, {100.0f, 100.0f}};
const SkColor colors[] = {
SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
SK_ColorWHITE, SK_ColorBLACK,
};
fShader = SkGradientShader::MakeLinear(
pts, colors, nullptr, SK_ARRAY_COUNT(colors),
SkShader::kClamp_TileMode);
}
void onDraw(int loops, SkCanvas*) final {
SkASSERT(fShader);
while (loops-- > 0) {
NullWStream nullStream;
SkPDFDocument doc(&nullStream, nullptr, 72, nullptr);
sk_sp<SkPDFObject> shader(
SkPDFShader::GetPDFShader(
&doc, 72, *fShader, SkMatrix::I(),
SkIRect::MakeWH(400,400), 72));
}
}
};
} // namespace } // namespace
DEF_BENCH(return new PDFImageBench;) DEF_BENCH(return new PDFImageBench;)
DEF_BENCH(return new PDFJpegImageBench;) DEF_BENCH(return new PDFJpegImageBench;)
DEF_BENCH(return new PDFCompressionBench;) DEF_BENCH(return new PDFCompressionBench;)
DEF_BENCH(return new PDFScalarBench;) DEF_BENCH(return new PDFScalarBench;)
DEF_BENCH(return new PDFShaderBench;)

View File

@ -8,6 +8,7 @@
#define SkPDFDocument_DEFINED #define SkPDFDocument_DEFINED
#include "SkDocument.h" #include "SkDocument.h"
#include "SkPDFCanon.h"
#include "SkPDFMetadata.h" #include "SkPDFMetadata.h"
#include "SkPDFFont.h" #include "SkPDFFont.h"

View File

@ -51,7 +51,8 @@ static void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) {
@param result The result ps function. @param result The result ps function.
*/ */
static void interpolateColorCode(SkScalar range, SkScalar* curColor, static void interpolateColorCode(SkScalar range, SkScalar* curColor,
SkScalar* prevColor, SkString* result) { SkScalar* prevColor,
SkDynamicMemoryWStream* result) {
SkASSERT(range != SkIntToScalar(0)); SkASSERT(range != SkIntToScalar(0));
static const int kColorComponents = 3; static const int kColorComponents = 3;
@ -71,32 +72,32 @@ static void interpolateColorCode(SkScalar range, SkScalar* curColor,
} }
if (!dupInput[0] && multiplier[0] == 0) { if (!dupInput[0] && multiplier[0] == 0) {
result->append("pop "); result->writeText("pop ");
} }
for (int i = 0; i < kColorComponents; i++) { for (int i = 0; i < kColorComponents; i++) {
// If the next components needs t and this component will consume a // If the next components needs t and this component will consume a
// copy, make another copy. // copy, make another copy.
if (dupInput[i] && multiplier[i] != 0) { if (dupInput[i] && multiplier[i] != 0) {
result->append("dup "); result->writeText("dup ");
} }
if (multiplier[i] == 0) { if (multiplier[i] == 0) {
result->appendScalar(prevColor[i]); SkPDFUtils::AppendScalar(prevColor[i], result);
result->append(" "); result->writeText(" ");
} else { } else {
if (multiplier[i] != 1) { if (multiplier[i] != 1) {
result->appendScalar(multiplier[i]); SkPDFUtils::AppendScalar(multiplier[i], result);
result->append(" mul "); result->writeText(" mul ");
} }
if (prevColor[i] != 0) { if (prevColor[i] != 0) {
result->appendScalar(prevColor[i]); SkPDFUtils::AppendScalar(prevColor[i], result);
result->append(" add "); result->writeText(" add ");
} }
} }
if (dupInput[i]) { 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, static void gradientFunctionCode(const SkShader::GradientInfo& info,
SkString* result) { SkDynamicMemoryWStream* result) {
/* We want to linearly interpolate from the previous color to the next. /* 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 Scale the colors from 0..255 to 0..1 and determine the multipliers
for interpolation. for interpolation.
@ -141,13 +142,13 @@ static void gradientFunctionCode(const SkShader::GradientInfo& info,
} }
// Clamp the initial color. // Clamp the initial color.
result->append("dup 0 le {pop "); result->writeText("dup 0 le {pop ");
result->appendScalar(colorData[0][0]); SkPDFUtils::AppendScalar(colorData[0][0], result);
result->append(" "); result->writeText(" ");
result->appendScalar(colorData[0][1]); SkPDFUtils::AppendScalar(colorData[0][1], result);
result->append(" "); result->writeText(" ");
result->appendScalar(colorData[0][2]); SkPDFUtils::AppendScalar(colorData[0][2], result);
result->append(" }\n"); result->writeText(" }\n");
// The gradient colors. // The gradient colors.
int gradients = 0; int gradients = 0;
@ -157,54 +158,55 @@ static void gradientFunctionCode(const SkShader::GradientInfo& info,
} }
gradients++; gradients++;
result->append("{dup "); result->writeText("{dup ");
result->appendScalar(info.fColorOffsets[i]); SkPDFUtils::AppendScalar(info.fColorOffsets[i], result);
result->append(" le {"); result->writeText(" le {");
if (info.fColorOffsets[i - 1] != 0) { if (info.fColorOffsets[i - 1] != 0) {
result->appendScalar(info.fColorOffsets[i - 1]); SkPDFUtils::AppendScalar(info.fColorOffsets[i - 1], result);
result->append(" sub\n"); result->writeText(" sub\n");
} }
interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1], interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1],
colorData[i], colorData[i - 1], result); colorData[i], colorData[i - 1], result);
result->append("}\n"); result->writeText("}\n");
} }
// Clamp the final color. // Clamp the final color.
result->append("{pop "); result->writeText("{pop ");
result->appendScalar(colorData[info.fColorCount - 1][0]); SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][0], result);
result->append(" "); result->writeText(" ");
result->appendScalar(colorData[info.fColorCount - 1][1]); SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][1], result);
result->append(" "); result->writeText(" ");
result->appendScalar(colorData[info.fColorCount - 1][2]); SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][2], result);
for (int i = 0 ; i < gradients + 1; i++) { 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. */ /* 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) { if (mode == SkShader::kRepeat_TileMode) {
result->append("dup truncate sub\n"); // Get the fractional part. result->writeText("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 0 le {1 add} if\n"); // Map (-1,0) => (0,1)
return; return;
} }
if (mode == SkShader::kMirror_TileMode) { if (mode == SkShader::kMirror_TileMode) {
// Map t mod 2 into [0, 1, 1, 0]. // Map t mod 2 into [0, 1, 1, 0].
// Code Stack // Code Stack
result->append("abs " // Map negative to positive. result->writeText("abs " // Map negative to positive.
"dup " // t.s t.s "dup " // t.s t.s
"truncate " // t.s t "truncate " // t.s t
"dup " // t.s t t "dup " // t.s t t
"cvi " // t.s t T "cvi " // t.s t T
"2 mod " // t.s t (i mod 2) "2 mod " // t.s t (i mod 2)
"1 eq " // t.s t true|false "1 eq " // t.s t true|false
"3 1 roll " // true|false t.s t "3 1 roll " // true|false t.s t
"sub " // true|false 0.s "sub " // true|false 0.s
"exch " // 0.s true|false "exch " // 0.s true|false
"{1 exch sub} if\n"); // 1 - 0.s|0.s "{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. * while the rest of the stack is preserved intact.
* inversePerspectiveMatrix is the inverse perspective matrix. * inversePerspectiveMatrix is the inverse perspective matrix.
*/ */
static SkString apply_perspective_to_coordinates( static void apply_perspective_to_coordinates(
const SkMatrix& inversePerspectiveMatrix) { const SkMatrix& inversePerspectiveMatrix,
SkString code; SkDynamicMemoryWStream* code) {
if (!inversePerspectiveMatrix.hasPerspective()) { if (!inversePerspectiveMatrix.hasPerspective()) {
return code; return;
} }
// Perspective matrix should be: // Perspective matrix should be:
@ -237,46 +239,46 @@ static SkString apply_perspective_to_coordinates(
// x = x / (p2 + p0 x + p1 y) // x = x / (p2 + p0 x + p1 y)
// Input on stack: x y // Input on stack: x y
code.append(" dup "); // x y y code->writeText(" dup "); // x y y
code.appendScalar(p1); // x y y p1 SkPDFUtils::AppendScalar(p1, code); // x y y p1
code.append(" mul " // x y y*p1 code->writeText(" mul " // x y y*p1
" 2 index "); // x y y*p1 x " 2 index "); // x y y*p1 x
code.appendScalar(p0); // x y y p1 x p0 SkPDFUtils::AppendScalar(p0, code); // x y y p1 x p0
code.append(" mul "); // x y y*p1 x*p0 code->writeText(" mul "); // x y y*p1 x*p0
code.appendScalar(p2); // x y y p1 x*p0 p2 SkPDFUtils::AppendScalar(p2, code); // x y y p1 x*p0 p2
code.append(" add " // 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 "add " // x y y*p1+x*p0+p2
"3 1 roll " // y*p1+x*p0+p2 x y "3 1 roll " // y*p1+x*p0+p2 x y
"2 index " // z x y y*p1+x*p0+p2 "2 index " // z x y y*p1+x*p0+p2
"div " // y*p1+x*p0+p2 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 "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 "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) "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) "exch\n"); // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2)
return code;
} }
static SkString linearCode(const SkShader::GradientInfo& info, static void linearCode(const SkShader::GradientInfo& info,
const SkMatrix& perspectiveRemover) { const SkMatrix& perspectiveRemover,
SkString function("{"); 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. function->writeText("pop\n"); // Just ditch the y value.
tileModeCode(info.fTileMode, &function); tileModeCode(info.fTileMode, function);
gradientFunctionCode(info, &function); gradientFunctionCode(info, function);
function.append("}"); function->writeText("}");
return function;
} }
static SkString radialCode(const SkShader::GradientInfo& info, static void radialCode(const SkShader::GradientInfo& info,
const SkMatrix& perspectiveRemover) { const SkMatrix& perspectiveRemover,
SkString function("{"); SkDynamicMemoryWStream* function) {
function->writeText("{");
function.append(apply_perspective_to_coordinates(perspectiveRemover)); apply_perspective_to_coordinates(perspectiveRemover, function);
// Find the distance from the origin. // Find the distance from the origin.
function.append("dup " // x y y function->writeText("dup " // x y y
"mul " // x y^2 "mul " // x y^2
"exch " // y^2 x "exch " // y^2 x
"dup " // y^2 x x "dup " // y^2 x x
@ -284,17 +286,17 @@ static SkString radialCode(const SkShader::GradientInfo& info,
"add " // y^2+x^2 "add " // y^2+x^2
"sqrt\n"); // sqrt(y^2+x^2) "sqrt\n"); // sqrt(y^2+x^2)
tileModeCode(info.fTileMode, &function); tileModeCode(info.fTileMode, function);
gradientFunctionCode(info, &function); gradientFunctionCode(info, function);
function.append("}"); function->writeText("}");
return function;
} }
/* Conical gradient shader, based on the Canvas spec for radial gradients /* Conical gradient shader, based on the Canvas spec for radial gradients
See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient
*/ */
static SkString twoPointConicalCode(const SkShader::GradientInfo& info, static void twoPointConicalCode(const SkShader::GradientInfo& info,
const SkMatrix& perspectiveRemover) { const SkMatrix& perspectiveRemover,
SkDynamicMemoryWStream* function) {
SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX; SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX;
SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY; SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY;
SkScalar r0 = info.fRadius[0]; 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 // 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. // 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). // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr).
function.appendScalar(dy); SkPDFUtils::AppendScalar(dy, function);
function.append(" mul exch "); function->writeText(" mul exch ");
function.appendScalar(dx); SkPDFUtils::AppendScalar(dx, function);
function.append(" mul add "); function->writeText(" mul add ");
function.appendScalar(SkScalarMul(r0, dr)); SkPDFUtils::AppendScalar(SkScalarMul(r0, dr), function);
function.append(" add -2 mul dup dup mul\n"); function->writeText(" add -2 mul dup dup mul\n");
// c = x^2 + y^2 + radius0^2 // c = x^2 + y^2 + radius0^2
function.append("4 2 roll dup mul exch dup mul add "); function->writeText("4 2 roll dup mul exch dup mul add ");
function.appendScalar(SkScalarMul(r0, r0)); SkPDFUtils::AppendScalar(SkScalarMul(r0, r0), function);
function.append(" sub dup 4 1 roll\n"); function->writeText(" sub dup 4 1 roll\n");
// Contents of the stack at this point: c, b, b^2, c // 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) { if (a == 0) {
// t = -c/b // t = -c/b
function.append("pop pop div neg dup "); function->writeText("pop pop div neg dup ");
// compute radius(t) // compute radius(t)
function.appendScalar(dr); SkPDFUtils::AppendScalar(dr, function);
function.append(" mul "); function->writeText(" mul ");
function.appendScalar(r0); SkPDFUtils::AppendScalar(r0, function);
function.append(" add\n"); function->writeText(" add\n");
// if r(t) < 0, then it's outside the cone // 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 { } else {
@ -349,70 +351,68 @@ static SkString twoPointConicalCode(const SkShader::GradientInfo& info,
// root t for which radius(t) > 0 // root t for which radius(t) > 0
// compute the discriminant (b^2 - 4ac) // compute the discriminant (b^2 - 4ac)
function.appendScalar(SkScalarMul(SkIntToScalar(4), a)); SkPDFUtils::AppendScalar(SkScalarMul(SkIntToScalar(4), a), function);
function.append(" mul sub dup\n"); function->writeText(" mul sub dup\n");
// if d >= 0, proceed // if d >= 0, proceed
function.append("0 ge {\n"); function->writeText("0 ge {\n");
// an intermediate value we'll use to compute the roots: // an intermediate value we'll use to compute the roots:
// q = -0.5 * (b +/- sqrt(d)) // q = -0.5 * (b +/- sqrt(d))
function.append("sqrt exch dup 0 lt {exch -1 mul} if"); function->writeText("sqrt exch dup 0 lt {exch -1 mul} if");
function.append(" add -0.5 mul dup\n"); function->writeText(" add -0.5 mul dup\n");
// first root = q / a // first root = q / a
function.appendScalar(a); SkPDFUtils::AppendScalar(a, function);
function.append(" div\n"); function->writeText(" div\n");
// second root = c / q // 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 // 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 // compute radius(t) for larger root
function.append("dup "); function->writeText("dup ");
function.appendScalar(dr); SkPDFUtils::AppendScalar(dr, function);
function.append(" mul "); function->writeText(" mul ");
function.appendScalar(r0); SkPDFUtils::AppendScalar(r0, function);
function.append(" add\n"); function->writeText(" add\n");
// if r(t) > 0, we have our t, pop off the smaller root and we're done // 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 // otherwise, throw out the larger one and try the smaller root
function.append("{pop dup\n"); function->writeText("{pop dup\n");
function.appendScalar(dr); SkPDFUtils::AppendScalar(dr, function);
function.append(" mul "); function->writeText(" mul ");
function.appendScalar(r0); SkPDFUtils::AppendScalar(r0, function);
function.append(" add\n"); function->writeText(" add\n");
// if r(t) < 0, push false, otherwise the smaller root is our t // if r(t) < 0, push false, otherwise the smaller root is our t
function.append("0 le {pop false} {true} ifelse\n"); function->writeText("0 le {pop false} {true} ifelse\n");
function.append("} ifelse\n"); function->writeText("} ifelse\n");
// d < 0, clear the stack and push false // 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 // if the pixel is in the cone, proceed to compute a color
function.append("{"); function->writeText("{");
tileModeCode(info.fTileMode, &function); tileModeCode(info.fTileMode, function);
gradientFunctionCode(info, &function); gradientFunctionCode(info, function);
// otherwise, just write black // otherwise, just write black
function.append("} {0 0 0} ifelse }"); function->writeText("} {0 0 0} ifelse }");
return function;
} }
static SkString sweepCode(const SkShader::GradientInfo& info, static void sweepCode(const SkShader::GradientInfo& info,
const SkMatrix& perspectiveRemover) { const SkMatrix& perspectiveRemover,
SkString function("{exch atan 360 div\n"); SkDynamicMemoryWStream* function) {
tileModeCode(info.fTileMode, &function); function->writeText("{exch atan 360 div\n");
gradientFunctionCode(info, &function); tileModeCode(info.fTileMode, function);
function.append("}"); gradientFunctionCode(info, function);
return function; function->writeText("}");
} }
static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& matrix) { static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& matrix) {
@ -689,12 +689,11 @@ sk_sp<SkPDFArray> SkPDFShader::MakeRangeObject() {
return range; return range;
} }
static sk_sp<SkPDFStream> make_ps_function(const SkString& psCode, static sk_sp<SkPDFStream> make_ps_function(
SkPDFArray* domain, std::unique_ptr<SkStreamAsset> psCode,
sk_sp<SkPDFObject> range) { SkPDFArray* domain,
SkAutoDataUnref funcData( sk_sp<SkPDFObject> range) {
SkData::NewWithCopy(psCode.c_str(), psCode.size())); auto result = sk_make_sp<SkPDFStream>(psCode.get());
auto result = sk_make_sp<SkPDFStream>(funcData.get());
result->insertInt("FunctionType", 4); result->insertInt("FunctionType", 4);
result->insertObject("Domain", sk_ref_sp(domain)); result->insertObject("Domain", sk_ref_sp(domain));
result->insertObject("Range", std::move(range)); result->insertObject("Range", std::move(range));
@ -705,8 +704,9 @@ SkPDFFunctionShader* SkPDFFunctionShader::Create(
SkPDFCanon* canon, SkAutoTDelete<SkPDFShader::State>* autoState) { SkPDFCanon* canon, SkAutoTDelete<SkPDFShader::State>* autoState) {
const SkPDFShader::State& state = **autoState; const SkPDFShader::State& state = **autoState;
SkString (*codeFunction)(const SkShader::GradientInfo& info, void (*codeFunction)(const SkShader::GradientInfo& info,
const SkMatrix& perspectiveRemover) = nullptr; const SkMatrix& perspectiveRemover,
SkDynamicMemoryWStream* function) = nullptr;
SkPoint transformPoints[2]; SkPoint transformPoints[2];
// Depending on the type of the gradient, we want to transform the // 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.fTop);
domain->appendScalar(bbox.fBottom); domain->appendScalar(bbox.fBottom);
SkString functionCode; SkDynamicMemoryWStream functionCode;
// The two point radial gradient further references // The two point radial gradient further references
// state.fInfo // state.fInfo
// in translating from x, y coordinates to the t parameter. So, we have // 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]); inverseMapperMatrix.mapRadius(info->fRadius[0]);
twoPointRadialInfo.fRadius[1] = twoPointRadialInfo.fRadius[1] =
inverseMapperMatrix.mapRadius(info->fRadius[1]); inverseMapperMatrix.mapRadius(info->fRadius[1]);
functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly); codeFunction(twoPointRadialInfo, perspectiveInverseOnly, &functionCode);
} else { } else {
functionCode = codeFunction(*info, perspectiveInverseOnly); codeFunction(*info, perspectiveInverseOnly, &functionCode);
} }
auto pdfShader = sk_make_sp<SkPDFDict>(); auto pdfShader = sk_make_sp<SkPDFDict>();
@ -806,7 +806,9 @@ SkPDFFunctionShader* SkPDFFunctionShader::Create(
// Call canon->makeRangeObject() instead of // Call canon->makeRangeObject() instead of
// SkPDFShader::MakeRangeObject() so that the canon can // SkPDFShader::MakeRangeObject() so that the canon can
// deduplicate. // 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()); canon->makeRangeObject());
pdfShader->insertObjRef("Function", std::move(function)); pdfShader->insertObjRef("Function", std::move(function));