194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary/* 294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * Copyright 2017 Google Inc. 394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * 494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * Use of this source code is governed by a BSD-style license that can be 594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * found in the LICENSE file. 694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary */ 794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary#include "SkPDFGradientShader.h" 994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 1094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary#include "SkOpts.h" 1194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary#include "SkPDFDocument.h" 1294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary#include "SkPDFFormXObject.h" 1394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary#include "SkPDFResourceDict.h" 1494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary#include "SkPDFUtils.h" 1594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 1694fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic uint32_t hash(const SkShader::GradientInfo& v) { 1794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary uint32_t buffer[] = { 1894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary (uint32_t)v.fColorCount, 1994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkOpts::hash(v.fColors, v.fColorCount * sizeof(SkColor)), 2094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkOpts::hash(v.fColorOffsets, v.fColorCount * sizeof(SkScalar)), 2194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkOpts::hash(v.fPoint, 2 * sizeof(SkPoint)), 2294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkOpts::hash(v.fRadius, 2 * sizeof(SkScalar)), 2394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary (uint32_t)v.fTileMode, 2494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary v.fGradientFlags, 2594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary }; 2694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return SkOpts::hash(buffer, sizeof(buffer)); 2794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 2894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 2994fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic uint32_t hash(const SkPDFGradientShader::Key& k) { 3094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary uint32_t buffer[] = { 3194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary (uint32_t)k.fType, 3294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary hash(k.fInfo), 3394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkOpts::hash(&k.fCanvasTransform, sizeof(SkMatrix)), 3494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkOpts::hash(&k.fShaderTransform, sizeof(SkMatrix)), 3594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkOpts::hash(&k.fBBox, sizeof(SkIRect)) 3694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary }; 3794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return SkOpts::hash(buffer, sizeof(buffer)); 3894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 3994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 4094fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic void unit_to_points_matrix(const SkPoint pts[2], SkMatrix* matrix) { 4194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkVector vec = pts[1] - pts[0]; 4294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar mag = vec.length(); 4394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar inv = mag ? SkScalarInvert(mag) : 0; 4494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 4594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary vec.scale(inv); 4694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary matrix->setSinCos(vec.fY, vec.fX); 4794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary matrix->preScale(mag, mag); 4894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary matrix->postTranslate(pts[0].fX, pts[0].fY); 4994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 5094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 5194fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic const int kColorComponents = 3; 5294fd66cc2502383628b2c5fb72a445460b752c35Hal Canarytypedef uint8_t ColorTuple[kColorComponents]; 5394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 5494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary/* Assumes t + startOffset is on the stack and does a linear interpolation on t 5594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary between startOffset and endOffset from prevColor to curColor (for each color 5694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary component), leaving the result in component order on the stack. It assumes 5794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary there are always 3 components per color. 5894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary @param range endOffset - startOffset 5994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary @param curColor[components] The current color components. 6094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary @param prevColor[components] The previous color components. 6194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary @param result The result ps function. 6294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary */ 6394fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic void interpolate_color_code(SkScalar range, const ColorTuple& curColor, 6494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const ColorTuple& prevColor, 6594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkDynamicMemoryWStream* result) { 6694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(range != SkIntToScalar(0)); 6794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 6894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Figure out how to scale each color component. 6994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar multiplier[kColorComponents]; 7094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 0; i < kColorComponents; i++) { 7194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary static const SkScalar kColorScale = SkScalarInvert(255); 7294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary multiplier[i] = kColorScale * (curColor[i] - prevColor[i]) / range; 7394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 7494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 7594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Calculate when we no longer need to keep a copy of the input parameter t. 7694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // If the last component to use t is i, then dupInput[0..i - 1] = true 7794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // and dupInput[i .. components] = false. 7894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary bool dupInput[kColorComponents]; 7994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary dupInput[kColorComponents - 1] = false; 8094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = kColorComponents - 2; i >= 0; i--) { 8194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0; 8294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 8394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 8494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (!dupInput[0] && multiplier[0] == 0) { 8594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("pop "); 8694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 8794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 8894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 0; i < kColorComponents; i++) { 8994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // If the next components needs t and this component will consume a 9094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // copy, make another copy. 9194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (dupInput[i] && multiplier[i] != 0) { 9294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("dup "); 9394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 9494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 9594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (multiplier[i] == 0) { 9694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendColorComponent(prevColor[i], result); 9794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText(" "); 9894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } else { 9994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (multiplier[i] != 1) { 10094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(multiplier[i], result); 10194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText(" mul "); 10294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 10394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (prevColor[i] != 0) { 10494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendColorComponent(prevColor[i], result); 10594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText(" add "); 10694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 10794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 10894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 10994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (dupInput[i]) { 11094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("exch\n"); 11194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 11294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 11394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 11494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 11594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary/* Generate Type 4 function code to map t=[0,1) to the passed gradient, 11694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary clamping at the edges of the range. The generated code will be of the form: 11794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (t < 0) { 11894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return colorData[0][r,g,b]; 11994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } else { 12094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (t < info.fColorOffsets[1]) { 12194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return linearinterpolation(colorData[0][r,g,b], 12294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorData[1][r,g,b]); 12394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } else { 12494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (t < info.fColorOffsets[2]) { 12594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return linearinterpolation(colorData[1][r,g,b], 12694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorData[2][r,g,b]); 12794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } else { 12894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 12994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary ... } else { 13094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return colorData[info.fColorCount - 1][r,g,b]; 13194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 13294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary ... 13394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 13494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 13594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary */ 13694fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic void gradient_function_code(const SkShader::GradientInfo& info, 13794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkDynamicMemoryWStream* result) { 13894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary /* We want to linearly interpolate from the previous color to the next. 13994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary Scale the colors from 0..255 to 0..1 and determine the multipliers 14094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for interpolation. 14194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}. 14294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary */ 14394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 14494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount); 14594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary ColorTuple *colorData = colorDataAlloc.get(); 14694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 0; i < info.fColorCount; i++) { 14794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorData[i][0] = SkColorGetR(info.fColors[i]); 14894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorData[i][1] = SkColorGetG(info.fColors[i]); 14994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorData[i][2] = SkColorGetB(info.fColors[i]); 15094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 15194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 15294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Clamp the initial color. 15394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("dup 0 le {pop "); 15494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendColorComponent(colorData[0][0], result); 15594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText(" "); 15694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendColorComponent(colorData[0][1], result); 15794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText(" "); 15894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendColorComponent(colorData[0][2], result); 15994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText(" }\n"); 16094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 16194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // The gradient colors. 16294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary int gradients = 0; 16394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 1 ; i < info.fColorCount; i++) { 16494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (info.fColorOffsets[i] == info.fColorOffsets[i - 1]) { 16594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary continue; 16694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 16794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary gradients++; 16894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 16994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("{dup "); 17094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(info.fColorOffsets[i], result); 17194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText(" le {"); 17294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (info.fColorOffsets[i - 1] != 0) { 17394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(info.fColorOffsets[i - 1], result); 17494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText(" sub\n"); 17594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 17694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 17794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary interpolate_color_code(info.fColorOffsets[i] - info.fColorOffsets[i - 1], 17894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorData[i], colorData[i - 1], result); 17994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("}\n"); 18094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 18194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 18294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Clamp the final color. 18394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("{pop "); 18494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendColorComponent(colorData[info.fColorCount - 1][0], result); 18594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText(" "); 18694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendColorComponent(colorData[info.fColorCount - 1][1], result); 18794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText(" "); 18894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendColorComponent(colorData[info.fColorCount - 1][2], result); 18994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 19094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 0 ; i < gradients + 1; i++) { 19194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("} ifelse\n"); 19294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 19394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 19494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 19594fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic sk_sp<SkPDFDict> createInterpolationFunction(const ColorTuple& color1, 19694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const ColorTuple& color2) { 19794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto retval = sk_make_sp<SkPDFDict>(); 19894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 19994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto c0 = sk_make_sp<SkPDFArray>(); 20094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary c0->appendColorComponent(color1[0]); 20194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary c0->appendColorComponent(color1[1]); 20294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary c0->appendColorComponent(color1[2]); 20394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary retval->insertObject("C0", std::move(c0)); 20494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 20594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto c1 = sk_make_sp<SkPDFArray>(); 20694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary c1->appendColorComponent(color2[0]); 20794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary c1->appendColorComponent(color2[1]); 20894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary c1->appendColorComponent(color2[2]); 20994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary retval->insertObject("C1", std::move(c1)); 21094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 21194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto domain = sk_make_sp<SkPDFArray>(); 21294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary domain->appendScalar(0); 21394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary domain->appendScalar(1.0f); 21494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary retval->insertObject("Domain", std::move(domain)); 21594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 21694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary retval->insertInt("FunctionType", 2); 21794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary retval->insertScalar("N", 1.0f); 21894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 21994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return retval; 22094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 22194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 22294fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic sk_sp<SkPDFDict> gradientStitchCode(const SkShader::GradientInfo& info) { 22394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto retval = sk_make_sp<SkPDFDict>(); 22494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 22594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // normalize color stops 22694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary int colorCount = info.fColorCount; 22794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkTDArray<SkColor> colors(info.fColors, colorCount); 22894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkTDArray<SkScalar> colorOffsets(info.fColorOffsets, colorCount); 22994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 23094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary int i = 1; 23194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary while (i < colorCount - 1) { 23294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // ensure stops are in order 23394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (colorOffsets[i - 1] > colorOffsets[i]) { 23494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorOffsets[i] = colorOffsets[i - 1]; 23594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 23694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 23794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // remove points that are between 2 coincident points 23894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if ((colorOffsets[i - 1] == colorOffsets[i]) && (colorOffsets[i] == colorOffsets[i + 1])) { 23994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorCount -= 1; 24094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colors.remove(i); 24194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorOffsets.remove(i); 24294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } else { 24394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary i++; 24494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 24594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 24694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // find coincident points and slightly move them over 24794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (i = 1; i < colorCount - 1; i++) { 24894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (colorOffsets[i - 1] == colorOffsets[i]) { 24994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorOffsets[i] += 0.00001f; 25094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 25194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 25294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // check if last 2 stops coincide 25394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (colorOffsets[i - 1] == colorOffsets[i]) { 25494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorOffsets[i - 1] -= 0.00001f; 25594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 25694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 25794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(colorCount); 25894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary ColorTuple *colorData = colorDataAlloc.get(); 25994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 0; i < colorCount; i++) { 26094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorData[i][0] = SkColorGetR(colors[i]); 26194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorData[i][1] = SkColorGetG(colors[i]); 26294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary colorData[i][2] = SkColorGetB(colors[i]); 26394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 26494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 26594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // no need for a stitch function if there are only 2 stops. 26694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (colorCount == 2) 26794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return createInterpolationFunction(colorData[0], colorData[1]); 26894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 26994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto encode = sk_make_sp<SkPDFArray>(); 27094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto bounds = sk_make_sp<SkPDFArray>(); 27194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto functions = sk_make_sp<SkPDFArray>(); 27294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 27394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto domain = sk_make_sp<SkPDFArray>(); 27494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary domain->appendScalar(0); 27594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary domain->appendScalar(1.0f); 27694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary retval->insertObject("Domain", std::move(domain)); 27794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary retval->insertInt("FunctionType", 3); 27894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 27994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 1; i < colorCount; i++) { 28094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (i > 1) { 28194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary bounds->appendScalar(colorOffsets[i-1]); 28294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 28394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 28494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary encode->appendScalar(0); 28594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary encode->appendScalar(1.0f); 28694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 28794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary functions->appendObject(createInterpolationFunction(colorData[i-1], colorData[i])); 28894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 28994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 29094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary retval->insertObject("Encode", std::move(encode)); 29194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary retval->insertObject("Bounds", std::move(bounds)); 29294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary retval->insertObject("Functions", std::move(functions)); 29394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 29494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return retval; 29594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 29694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 29794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary/* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */ 29894fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic void tileModeCode(SkShader::TileMode mode, 29994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkDynamicMemoryWStream* result) { 30094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (mode == SkShader::kRepeat_TileMode) { 30194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("dup truncate sub\n"); // Get the fractional part. 30294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1) 30394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return; 30494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 30594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 30694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (mode == SkShader::kMirror_TileMode) { 30794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Map t mod 2 into [0, 1, 1, 0]. 30894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Code Stack 30994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->writeText("abs " // Map negative to positive. 31094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "dup " // t.s t.s 31194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "truncate " // t.s t 31294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "dup " // t.s t t 31394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "cvi " // t.s t T 31494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "2 mod " // t.s t (i mod 2) 31594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "1 eq " // t.s t true|false 31694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "3 1 roll " // true|false t.s t 31794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "sub " // true|false 0.s 31894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "exch " // 0.s true|false 31994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "{1 exch sub} if\n"); // 1 - 0.s|0.s 32094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 32194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 32294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 32394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary/** 32494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * Returns PS function code that applies inverse perspective 32594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * to a x, y point. 32694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * The function assumes that the stack has at least two elements, 32794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * and that the top 2 elements are numeric values. 32894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * After executing this code on a PS stack, the last 2 elements are updated 32994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * while the rest of the stack is preserved intact. 33094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary * inversePerspectiveMatrix is the inverse perspective matrix. 33194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary */ 33294fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic void apply_perspective_to_coordinates(const SkMatrix& inversePerspectiveMatrix, 33394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkDynamicMemoryWStream* code) { 33494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (!inversePerspectiveMatrix.hasPerspective()) { 33594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return; 33694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 33794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 33894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Perspective matrix should be: 33994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // 1 0 0 34094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // 0 1 0 34194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // p0 p1 p2 34294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 34394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar p0 = inversePerspectiveMatrix[SkMatrix::kMPersp0]; 34494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar p1 = inversePerspectiveMatrix[SkMatrix::kMPersp1]; 34594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar p2 = inversePerspectiveMatrix[SkMatrix::kMPersp2]; 34694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 34794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // y = y / (p2 + p0 x + p1 y) 34894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // x = x / (p2 + p0 x + p1 y) 34994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 35094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Input on stack: x y 35194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary code->writeText(" dup "); // x y y 35294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(p1, code); // x y y p1 35394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary code->writeText(" mul " // x y y*p1 35494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary " 2 index "); // x y y*p1 x 35594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(p0, code); // x y y p1 x p0 35694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary code->writeText(" mul "); // x y y*p1 x*p0 35794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(p2, code); // x y y p1 x*p0 p2 35894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary code->writeText(" add " // x y y*p1 x*p0+p2 35994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "add " // x y y*p1+x*p0+p2 36094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "3 1 roll " // y*p1+x*p0+p2 x y 36194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "2 index " // z x y y*p1+x*p0+p2 36294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "div " // y*p1+x*p0+p2 x y/(y*p1+x*p0+p2) 36394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "3 1 roll " // y/(y*p1+x*p0+p2) y*p1+x*p0+p2 x 36494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "exch " // y/(y*p1+x*p0+p2) x y*p1+x*p0+p2 36594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "div " // y/(y*p1+x*p0+p2) x/(y*p1+x*p0+p2) 36694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "exch\n"); // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2) 36794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 36894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 36994fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic void linearCode(const SkShader::GradientInfo& info, 37094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkMatrix& perspectiveRemover, 37194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkDynamicMemoryWStream* function) { 37294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("{"); 37394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 37494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary apply_perspective_to_coordinates(perspectiveRemover, function); 37594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 37694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("pop\n"); // Just ditch the y value. 37794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary tileModeCode(info.fTileMode, function); 37894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary gradient_function_code(info, function); 37994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("}"); 38094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 38194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 38294fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic void radialCode(const SkShader::GradientInfo& info, 38394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkMatrix& perspectiveRemover, 38494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkDynamicMemoryWStream* function) { 38594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("{"); 38694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 38794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary apply_perspective_to_coordinates(perspectiveRemover, function); 38894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 38994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Find the distance from the origin. 39094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("dup " // x y y 39194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "mul " // x y^2 39294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "exch " // y^2 x 39394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "dup " // y^2 x x 39494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "mul " // y^2 x^2 39594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "add " // y^2+x^2 39694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "sqrt\n"); // sqrt(y^2+x^2) 39794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 39894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary tileModeCode(info.fTileMode, function); 39994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary gradient_function_code(info, function); 40094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("}"); 40194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 40294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 40394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary/* Conical gradient shader, based on the Canvas spec for radial gradients 40494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient 40594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary */ 40694fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic void twoPointConicalCode(const SkShader::GradientInfo& info, 40794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkMatrix& perspectiveRemover, 40894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkDynamicMemoryWStream* function) { 40994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX; 41094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY; 41194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar r0 = info.fRadius[0]; 41294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar dr = info.fRadius[1] - info.fRadius[0]; 41394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar a = dx * dx + dy * dy - dr * dr; 41494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 41594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // First compute t, if the pixel falls outside the cone, then we'll end 41694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // with 'false' on the stack, otherwise we'll push 'true' with t below it 41794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 41894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // We start with a stack of (x y), copy it and then consume one copy in 41994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // order to calculate b and the other to calculate c. 42094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("{"); 42194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 42294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary apply_perspective_to_coordinates(perspectiveRemover, function); 42394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 42494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("2 copy "); 42594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 42694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr). 42794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(dy, function); 42894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" mul exch "); 42994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(dx, function); 43094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" mul add "); 43194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(r0 * dr, function); 43294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" add -2 mul dup dup mul\n"); 43394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 43494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // c = x^2 + y^2 + radius0^2 43594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("4 2 roll dup mul exch dup mul add "); 43694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(r0 * r0, function); 43794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" sub dup 4 1 roll\n"); 43894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 43994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Contents of the stack at this point: c, b, b^2, c 44094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 44194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // if a = 0, then we collapse to a simpler linear case 44294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (a == 0) { 44394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 44494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // t = -c/b 44594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("pop pop div neg dup "); 44694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 44794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // compute radius(t) 44894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(dr, function); 44994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" mul "); 45094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(r0, function); 45194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" add\n"); 45294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 45394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // if r(t) < 0, then it's outside the cone 45494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("0 lt {pop false} {true} ifelse\n"); 45594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 45694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } else { 45794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 45894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // quadratic case: the Canvas spec wants the largest 45994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // root t for which radius(t) > 0 46094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 46194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // compute the discriminant (b^2 - 4ac) 46294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(a * 4, function); 46394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" mul sub dup\n"); 46494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 46594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // if d >= 0, proceed 46694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("0 ge {\n"); 46794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 46894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // an intermediate value we'll use to compute the roots: 46994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // q = -0.5 * (b +/- sqrt(d)) 47094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("sqrt exch dup 0 lt {exch -1 mul} if"); 47194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" add -0.5 mul dup\n"); 47294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 47394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // first root = q / a 47494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(a, function); 47594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" div\n"); 47694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 47794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // second root = c / q 47894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("3 1 roll div\n"); 47994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 48094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // put the larger root on top of the stack 48194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("2 copy gt {exch} if\n"); 48294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 48394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // compute radius(t) for larger root 48494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("dup "); 48594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(dr, function); 48694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" mul "); 48794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(r0, function); 48894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" add\n"); 48994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 49094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // if r(t) > 0, we have our t, pop off the smaller root and we're done 49194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" 0 gt {exch pop true}\n"); 49294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 49394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // otherwise, throw out the larger one and try the smaller root 49494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("{pop dup\n"); 49594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(dr, function); 49694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" mul "); 49794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendScalar(r0, function); 49894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText(" add\n"); 49994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 50094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // if r(t) < 0, push false, otherwise the smaller root is our t 50194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("0 le {pop false} {true} ifelse\n"); 50294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("} ifelse\n"); 50394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 50494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // d < 0, clear the stack and push false 50594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("} {pop pop pop false} ifelse\n"); 50694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 50794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 50894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // if the pixel is in the cone, proceed to compute a color 50994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("{"); 51094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary tileModeCode(info.fTileMode, function); 51194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary gradient_function_code(info, function); 51294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 51394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // otherwise, just write black 51494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("} {0 0 0} ifelse }"); 51594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 51694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 51794fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic void sweepCode(const SkShader::GradientInfo& info, 51894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkMatrix& perspectiveRemover, 51994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkDynamicMemoryWStream* function) { 52094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("{exch atan 360 div\n"); 52194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary tileModeCode(info.fTileMode, function); 52294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary gradient_function_code(info, function); 52394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary function->writeText("}"); 52494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 52594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 52694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 52794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary// catch cases where the inner just touches the outer circle 52894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary// and make the inner circle just inside the outer one to match raster 52994fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic void FixUpRadius(const SkPoint& p1, SkScalar& r1, const SkPoint& p2, SkScalar& r2) { 53094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // detect touching circles 53194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar distance = SkPoint::Distance(p1, p2); 53294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar subtractRadii = fabs(r1 - r2); 53394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (fabs(distance - subtractRadii) < 0.002f) { 53494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (r1 > r2) { 53594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary r1 += 0.002f; 53694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } else { 53794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary r2 += 0.002f; 53894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 53994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 54094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 54194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 54294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary// Finds affine and persp such that in = affine * persp. 54394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary// but it returns the inverse of perspective matrix. 54494fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic bool split_perspective(const SkMatrix in, SkMatrix* affine, 54594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkMatrix* perspectiveInverse) { 54694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar p2 = in[SkMatrix::kMPersp2]; 54794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 54894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (SkScalarNearlyZero(p2)) { 54994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return false; 55094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 55194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 55294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar zero = SkIntToScalar(0); 55394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar one = SkIntToScalar(1); 55494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 55594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar sx = in[SkMatrix::kMScaleX]; 55694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar kx = in[SkMatrix::kMSkewX]; 55794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar tx = in[SkMatrix::kMTransX]; 55894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar ky = in[SkMatrix::kMSkewY]; 55994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar sy = in[SkMatrix::kMScaleY]; 56094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar ty = in[SkMatrix::kMTransY]; 56194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar p0 = in[SkMatrix::kMPersp0]; 56294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkScalar p1 = in[SkMatrix::kMPersp1]; 56394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 56494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Perspective matrix would be: 56594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // 1 0 0 56694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // 0 1 0 56794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // p0 p1 p2 56894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // But we need the inverse of persp. 56994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary perspectiveInverse->setAll(one, zero, zero, 57094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary zero, one, zero, 57194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary -p0/p2, -p1/p2, 1/p2); 57294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 57394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary affine->setAll(sx - p0 * tx / p2, kx - p1 * tx / p2, tx / p2, 57494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary ky - p0 * ty / p2, sy - p1 * ty / p2, ty / p2, 57594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary zero, zero, one); 57694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 57794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return true; 57894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 57994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 58094fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic sk_sp<SkPDFArray> make_range_object() { 58194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto range = sk_make_sp<SkPDFArray>(); 58294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary range->reserve(6); 58394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary range->appendInt(0); 58494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary range->appendInt(1); 58594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary range->appendInt(0); 58694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary range->appendInt(1); 58794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary range->appendInt(0); 58894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary range->appendInt(1); 58994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return range; 59094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 59194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 59294fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic sk_sp<SkPDFStream> make_ps_function( 59394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary std::unique_ptr<SkStreamAsset> psCode, 59494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary sk_sp<SkPDFArray> domain, 59594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary sk_sp<SkPDFObject> range) { 59694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto result = sk_make_sp<SkPDFStream>(std::move(psCode)); 59794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->dict()->insertInt("FunctionType", 4); 59894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->dict()->insertObject("Domain", std::move(domain)); 59994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary result->dict()->insertObject("Range", std::move(range)); 60094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return result; 60194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 60294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 60394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 60494fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic sk_sp<SkPDFDict> make_function_shader(SkPDFCanon* canon, 60594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkPDFGradientShader::Key& state) { 60694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPoint transformPoints[2]; 60794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkShader::GradientInfo& info = state.fInfo; 60894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkMatrix finalMatrix = state.fCanvasTransform; 60994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary finalMatrix.preConcat(state.fShaderTransform); 61094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 61194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary bool doStitchFunctions = (state.fType == SkShader::kLinear_GradientType || 61294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary state.fType == SkShader::kRadial_GradientType || 61394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary state.fType == SkShader::kConical_GradientType) && 61494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary info.fTileMode == SkShader::kClamp_TileMode && 61594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary !finalMatrix.hasPerspective(); 61694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 61794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto domain = sk_make_sp<SkPDFArray>(); 61894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 61994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary int32_t shadingType = 1; 62094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto pdfShader = sk_make_sp<SkPDFDict>(); 62194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // The two point radial gradient further references 62294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // state.fInfo 62394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // in translating from x, y coordinates to the t parameter. So, we have 62494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // to transform the points and radii according to the calculated matrix. 62594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (doStitchFunctions) { 62694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary pdfShader->insertObject("Function", gradientStitchCode(info)); 62794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary shadingType = (state.fType == SkShader::kLinear_GradientType) ? 2 : 3; 62894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 62994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto extend = sk_make_sp<SkPDFArray>(); 63094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary extend->reserve(2); 63194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary extend->appendBool(true); 63294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary extend->appendBool(true); 63394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary pdfShader->insertObject("Extend", std::move(extend)); 63494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 63594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto coords = sk_make_sp<SkPDFArray>(); 63694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (state.fType == SkShader::kConical_GradientType) { 63794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->reserve(6); 63894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar r1 = info.fRadius[0]; 63994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkScalar r2 = info.fRadius[1]; 64094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPoint pt1 = info.fPoint[0]; 64194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPoint pt2 = info.fPoint[1]; 64294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary FixUpRadius(pt1, r1, pt2, r2); 64394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 64494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt1.fX); 64594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt1.fY); 64694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(r1); 64794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 64894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt2.fX); 64994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt2.fY); 65094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(r2); 65194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } else if (state.fType == SkShader::kRadial_GradientType) { 65294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->reserve(6); 65394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkPoint& pt1 = info.fPoint[0]; 65494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 65594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt1.fX); 65694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt1.fY); 65794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(0); 65894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 65994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt1.fX); 66094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt1.fY); 66194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(info.fRadius[0]); 66294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } else { 66394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->reserve(4); 66494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkPoint& pt1 = info.fPoint[0]; 66594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkPoint& pt2 = info.fPoint[1]; 66694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 66794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt1.fX); 66894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt1.fY); 66994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 67094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt2.fX); 67194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary coords->appendScalar(pt2.fY); 67294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 67394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 67494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary pdfShader->insertObject("Coords", std::move(coords)); 67594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } else { 67694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Depending on the type of the gradient, we want to transform the 67794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // coordinate space in different ways. 67894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary transformPoints[0] = info.fPoint[0]; 67994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary transformPoints[1] = info.fPoint[1]; 68094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary switch (state.fType) { 68194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary case SkShader::kLinear_GradientType: 68294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary break; 68394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary case SkShader::kRadial_GradientType: 68494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary transformPoints[1] = transformPoints[0]; 68594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary transformPoints[1].fX += info.fRadius[0]; 68694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary break; 68794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary case SkShader::kConical_GradientType: { 68894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary transformPoints[1] = transformPoints[0]; 68994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary transformPoints[1].fX += SK_Scalar1; 69094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary break; 69194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 69294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary case SkShader::kSweep_GradientType: 69394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary transformPoints[1] = transformPoints[0]; 69494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary transformPoints[1].fX += SK_Scalar1; 69594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary break; 69694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary case SkShader::kColor_GradientType: 69794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary case SkShader::kNone_GradientType: 69894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary default: 69994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return nullptr; 70094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 70194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 70294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Move any scaling (assuming a unit gradient) or translation 70394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // (and rotation for linear gradient), of the final gradient from 70494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // info.fPoints to the matrix (updating bbox appropriately). Now 70594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // the gradient can be drawn on on the unit segment. 70694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkMatrix mapperMatrix; 70794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary unit_to_points_matrix(transformPoints, &mapperMatrix); 70894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 70994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary finalMatrix.preConcat(mapperMatrix); 71094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 71194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Preserves as much as posible in the final matrix, and only removes 71294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // the perspective. The inverse of the perspective is stored in 71394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // perspectiveInverseOnly matrix and has 3 useful numbers 71494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // (p0, p1, p2), while everything else is either 0 or 1. 71594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // In this way the shader will handle it eficiently, with minimal code. 71694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkMatrix perspectiveInverseOnly = SkMatrix::I(); 71794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (finalMatrix.hasPerspective()) { 71894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (!split_perspective(finalMatrix, 71994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary &finalMatrix, &perspectiveInverseOnly)) { 72094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return nullptr; 72194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 72294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 72394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 72494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkRect bbox; 72594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary bbox.set(state.fBBox); 72694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (!SkPDFUtils::InverseTransformBBox(finalMatrix, &bbox)) { 72794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return nullptr; 72894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 72994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary domain->reserve(4); 73094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary domain->appendScalar(bbox.fLeft); 73194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary domain->appendScalar(bbox.fRight); 73294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary domain->appendScalar(bbox.fTop); 73394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary domain->appendScalar(bbox.fBottom); 73494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 73594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkDynamicMemoryWStream functionCode; 73694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 73794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkShader::GradientInfo infoCopy = info; 73894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 73994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (state.fType == SkShader::kConical_GradientType) { 74094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkMatrix inverseMapperMatrix; 74194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (!mapperMatrix.invert(&inverseMapperMatrix)) { 74294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return nullptr; 74394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 74494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary inverseMapperMatrix.mapPoints(infoCopy.fPoint, 2); 74594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary infoCopy.fRadius[0] = inverseMapperMatrix.mapRadius(info.fRadius[0]); 74694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary infoCopy.fRadius[1] = inverseMapperMatrix.mapRadius(info.fRadius[1]); 74794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 74894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary switch (state.fType) { 74994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary case SkShader::kLinear_GradientType: 75094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary linearCode(infoCopy, perspectiveInverseOnly, &functionCode); 75194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary break; 75294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary case SkShader::kRadial_GradientType: 75394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary radialCode(infoCopy, perspectiveInverseOnly, &functionCode); 75494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary break; 75594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary case SkShader::kConical_GradientType: 75694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary twoPointConicalCode(infoCopy, perspectiveInverseOnly, &functionCode); 75794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary break; 75894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary case SkShader::kSweep_GradientType: 75994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary sweepCode(infoCopy, perspectiveInverseOnly, &functionCode); 76094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary break; 76194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary default: 76294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(false); 76394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 76494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary pdfShader->insertObject("Domain", domain); 76594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 76694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary sk_sp<SkPDFArray>& rangeObject = canon->fRangeObject; 76794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (!rangeObject) { 76894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary rangeObject = make_range_object(); 76994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 77094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary pdfShader->insertObjRef("Function", 77194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary make_ps_function(functionCode.detachAsStream(), std::move(domain), 77294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary rangeObject)); 77394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 77494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 77594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary pdfShader->insertInt("ShadingType", shadingType); 77694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary pdfShader->insertName("ColorSpace", "DeviceRGB"); 77794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 77894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto pdfFunctionShader = sk_make_sp<SkPDFDict>("Pattern"); 77994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary pdfFunctionShader->insertInt("PatternType", 2); 78094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary pdfFunctionShader->insertObject("Matrix", SkPDFUtils::MatrixToArray(finalMatrix)); 78194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary pdfFunctionShader->insertObject("Shading", std::move(pdfShader)); 78294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 78394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return pdfFunctionShader; 78494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 78594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 7862d171397f863699eb7804b814994d4c2fcb00cb7Hal Canarystatic sk_sp<SkPDFObject> find_pdf_shader(SkPDFDocument* doc, 7872d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary SkPDFGradientShader::Key key, 7882d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary bool keyHasAlpha); 78994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 79094fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic sk_sp<SkPDFDict> get_gradient_resource_dict(SkPDFObject* functionShader, 79194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFObject* gState) { 79294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkTDArray<SkPDFObject*> patterns; 79394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (functionShader) { 79494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary patterns.push(functionShader); 79594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 79694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkTDArray<SkPDFObject*> graphicStates; 79794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (gState) { 79894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary graphicStates.push(gState); 79994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 80094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return SkPDFResourceDict::Make(&graphicStates, &patterns, nullptr, nullptr); 80194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 80294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 80394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary// Creates a content stream which fills the pattern P0 across bounds. 80494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary// @param gsIndex A graphics state resource index to apply, or <0 if no 80594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary// graphics state to apply. 80694fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic std::unique_ptr<SkStreamAsset> create_pattern_fill_content(int gsIndex, SkRect& bounds) { 80794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkDynamicMemoryWStream content; 80894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (gsIndex >= 0) { 80994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::ApplyGraphicState(gsIndex, &content); 81094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 81194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::ApplyPattern(0, &content); 81294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::AppendRectangle(bounds, &content); 81394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPath::kEvenOdd_FillType, &content); 81494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return content.detachAsStream(); 81594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 81694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 81794fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic bool gradient_has_alpha(const SkPDFGradientShader::Key& key) { 81894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(key.fType != SkShader::kNone_GradientType); 81994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 0; i < key.fInfo.fColorCount; i++) { 82094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if ((SkAlpha)SkColorGetA(key.fInfo.fColors[i]) != SK_AlphaOPAQUE) { 82194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return true; 82294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 82394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 82494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return false; 82594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 82694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 82794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary// warning: does not set fHash on new key. (Both callers need to change fields.) 82894fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic SkPDFGradientShader::Key clone_key(const SkPDFGradientShader::Key& k) { 82994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFGradientShader::Key clone = { 83094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary k.fType, 83194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary k.fInfo, // change pointers later. 83294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary std::unique_ptr<SkColor[]>(new SkColor[k.fInfo.fColorCount]), 83394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary std::unique_ptr<SkScalar[]>(new SkScalar[k.fInfo.fColorCount]), 83494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary k.fCanvasTransform, 83594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary k.fShaderTransform, 83694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary k.fBBox, 0}; 83794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary clone.fInfo.fColors = clone.fColors.get(); 83894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary clone.fInfo.fColorOffsets = clone.fStops.get(); 83994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 0; i < clone.fInfo.fColorCount; i++) { 84094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary clone.fInfo.fColorOffsets[i] = k.fInfo.fColorOffsets[i]; 84194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary clone.fInfo.fColors[i] = k.fInfo.fColors[i]; 84294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 84394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return clone; 84494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 84594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 84694fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic sk_sp<SkPDFObject> create_smask_graphic_state(SkPDFDocument* doc, 84794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkPDFGradientShader::Key& state) { 84894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(state.fType != SkShader::kNone_GradientType); 84994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFGradientShader::Key luminosityState = clone_key(state); 85094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 0; i < luminosityState.fInfo.fColorCount; i++) { 85194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkAlpha alpha = SkColorGetA(luminosityState.fInfo.fColors[i]); 85294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary luminosityState.fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha); 85394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 85494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary luminosityState.fHash = hash(luminosityState); 85594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 85694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(!gradient_has_alpha(luminosityState)); 8572d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary sk_sp<SkPDFObject> luminosityShader = find_pdf_shader(doc, std::move(luminosityState), false); 85894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary sk_sp<SkPDFDict> resources = get_gradient_resource_dict(luminosityShader.get(), nullptr); 85994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkRect bbox = SkRect::Make(state.fBBox); 86094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary sk_sp<SkPDFObject> alphaMask = SkPDFMakeFormXObject(create_pattern_fill_content(-1, bbox), 86194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::RectToArray(bbox), 86294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary std::move(resources), 86394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkMatrix::I(), 86494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary "DeviceRGB"); 86594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return SkPDFGraphicState::GetSMaskGraphicState( 86694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary std::move(alphaMask), false, 86794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFGraphicState::kLuminosity_SMaskMode, doc->canon()); 86894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 86994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 87094fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic sk_sp<SkPDFStream> make_alpha_function_shader(SkPDFDocument* doc, 87194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkPDFGradientShader::Key& state) { 87294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(state.fType != SkShader::kNone_GradientType); 87394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFGradientShader::Key opaqueState = clone_key(state); 87494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary for (int i = 0; i < opaqueState.fInfo.fColorCount; i++) { 87594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary opaqueState.fInfo.fColors[i] = SkColorSetA(opaqueState.fInfo.fColors[i], SK_AlphaOPAQUE); 87694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 87794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary opaqueState.fHash = hash(opaqueState); 87894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 87994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(!gradient_has_alpha(opaqueState)); 88094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkRect bbox = SkRect::Make(state.fBBox); 8812d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary sk_sp<SkPDFObject> colorShader = find_pdf_shader(doc, std::move(opaqueState), false); 88294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary if (!colorShader) { 88394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return nullptr; 88494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary } 88594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 88694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // Create resource dict with alpha graphics state as G0 and 88794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary // pattern shader as P0, then write content stream. 88894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary sk_sp<SkPDFObject> alphaGs = create_smask_graphic_state(doc, state); 88994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 89094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary sk_sp<SkPDFDict> resourceDict = 89194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary get_gradient_resource_dict(colorShader.get(), alphaGs.get()); 89294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 89394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary std::unique_ptr<SkStreamAsset> colorStream(create_pattern_fill_content(0, bbox)); 89494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary auto alphaFunctionShader = sk_make_sp<SkPDFStream>(std::move(colorStream)); 89594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 89694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::PopulateTilingPatternDict(alphaFunctionShader->dict(), bbox, 89794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary std::move(resourceDict), SkMatrix::I()); 89894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return alphaFunctionShader; 89994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 90094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 90194fd66cc2502383628b2c5fb72a445460b752c35Hal Canarystatic SkPDFGradientShader::Key make_key(const SkShader* shader, 90294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkMatrix& canvasTransform, 90394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkIRect& bbox) { 90494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFGradientShader::Key key = { 90594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkShader::kNone_GradientType, 90694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary {0, nullptr, nullptr, {{0, 0}, {0, 0}}, {0, 0}, SkShader::kClamp_TileMode, 0}, 90794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary nullptr, 90894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary nullptr, 90994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary canvasTransform, 91094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFUtils::GetShaderLocalMatrix(shader), 91194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary bbox, 0}; 91294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary key.fType = shader->asAGradient(&key.fInfo); 91394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(SkShader::kNone_GradientType != key.fType); 91494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(key.fInfo.fColorCount > 0); 91594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary key.fColors.reset(new SkColor[key.fInfo.fColorCount]); 91694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary key.fStops.reset(new SkScalar[key.fInfo.fColorCount]); 91794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary key.fInfo.fColors = key.fColors.get(); 91894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary key.fInfo.fColorOffsets = key.fStops.get(); 91994fd66cc2502383628b2c5fb72a445460b752c35Hal Canary (void)shader->asAGradient(&key.fInfo); 92094fd66cc2502383628b2c5fb72a445460b752c35Hal Canary key.fHash = hash(key); 92194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary return key; 92294fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 92394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary 9242d171397f863699eb7804b814994d4c2fcb00cb7Hal Canarystatic sk_sp<SkPDFObject> find_pdf_shader(SkPDFDocument* doc, 9252d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary SkPDFGradientShader::Key key, 9262d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary bool keyHasAlpha) { 9272d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary SkASSERT(gradient_has_alpha(key) == keyHasAlpha); 9282d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary SkPDFCanon* canon = doc->canon(); 9292d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary if (sk_sp<SkPDFObject>* ptr = canon->fGradientPatternMap.find(key)) { 9302d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary return *ptr; 9312d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary } 9322d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary sk_sp<SkPDFObject> pdfShader; 9332d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary if (keyHasAlpha) { 9342d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary pdfShader = make_alpha_function_shader(doc, key); 9352d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary } else { 9362d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary pdfShader = make_function_shader(canon, key); 9372d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary } 9382d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary canon->fGradientPatternMap.set(std::move(key), pdfShader); 9392d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary return pdfShader; 9402d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary} 9412d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary 94294fd66cc2502383628b2c5fb72a445460b752c35Hal Canarysk_sp<SkPDFObject> SkPDFGradientShader::Make(SkPDFDocument* doc, 94394fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkShader* shader, 94494fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkMatrix& canvasTransform, 94594fd66cc2502383628b2c5fb72a445460b752c35Hal Canary const SkIRect& bbox) { 94694fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(shader); 94794fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkASSERT(SkShader::kNone_GradientType != shader->asAGradient(nullptr)); 94894fd66cc2502383628b2c5fb72a445460b752c35Hal Canary SkPDFGradientShader::Key key = make_key(shader, canvasTransform, bbox); 9492d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary bool alpha = gradient_has_alpha(key); 9502d171397f863699eb7804b814994d4c2fcb00cb7Hal Canary return find_pdf_shader(doc, std::move(key), alpha); 95194fd66cc2502383628b2c5fb72a445460b752c35Hal Canary} 952