1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 2da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc. 4da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org * 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 7da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 8da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 10da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkPDFShader.h" 11da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 12421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org#include "SkData.h" 13fb62b3d423fa34c672df42f47017dbef087d19e9halcanary#include "SkPDFCanon.h" 14da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkPDFDevice.h" 1593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org#include "SkPDFFormXObject.h" 1693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org#include "SkPDFGraphicState.h" 1747401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org#include "SkPDFResourceDict.h" 18da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkPDFUtils.h" 19da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkScalar.h" 20da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkStream.h" 21316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com#include "SkTemplates.h" 22da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkTypes.h" 23da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 247b4d4c7a4668f771641aaed88b83d22d5efe6873fmalitastatic bool inverse_transform_bbox(const SkMatrix& matrix, SkRect* bbox) { 25da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix inverse; 26b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org if (!matrix.invert(&inverse)) { 27386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return false; 28b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org } 29da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverse.mapRect(bbox); 30386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return true; 31da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 32da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 33da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) { 34da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkVector vec = pts[1] - pts[0]; 35da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar mag = vec.length(); 36da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar inv = mag ? SkScalarInvert(mag) : 0; 37da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 38da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org vec.scale(inv); 39da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org matrix->setSinCos(vec.fY, vec.fX); 40da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org matrix->preScale(mag, mag); 41ace2269edfed9dfd3097597f1698921aaddf80a1commit-bot@chromium.org matrix->postTranslate(pts[0].fX, pts[0].fY); 42da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 43da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 44da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* Assumes t + startOffset is on the stack and does a linear interpolation on t 45da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org between startOffset and endOffset from prevColor to curColor (for each color 4653648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com component), leaving the result in component order on the stack. It assumes 4753648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com there are always 3 components per color. 48da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param range endOffset - startOffset 49da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param curColor[components] The current color components. 50da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param prevColor[components] The previous color components. 51da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param result The result ps function. 52da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 53da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void interpolateColorCode(SkScalar range, SkScalar* curColor, 5453648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com SkScalar* prevColor, SkString* result) { 558135323f70b38e465761ab3e9817183750e3864dedisonn@google.com SkASSERT(range != SkIntToScalar(0)); 5653648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com static const int kColorComponents = 3; 5753648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com 58da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Figure out how to scale each color component. 5953648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com SkScalar multiplier[kColorComponents]; 6053648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com for (int i = 0; i < kColorComponents; i++) { 6180ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed multiplier[i] = (curColor[i] - prevColor[i]) / range; 62da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 63da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 64da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Calculate when we no longer need to keep a copy of the input parameter t. 65da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // If the last component to use t is i, then dupInput[0..i - 1] = true 66da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // and dupInput[i .. components] = false. 6753648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com bool dupInput[kColorComponents]; 6853648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com dupInput[kColorComponents - 1] = false; 6953648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com for (int i = kColorComponents - 2; i >= 0; i--) { 70da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0; 71da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 72da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 73da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!dupInput[0] && multiplier[0] == 0) { 74da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("pop "); 75da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 76da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 7753648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com for (int i = 0; i < kColorComponents; i++) { 78b862204352f1a6028e0bfafd25df1cbca114208bvandebo@chromium.org // If the next components needs t and this component will consume a 79b862204352f1a6028e0bfafd25df1cbca114208bvandebo@chromium.org // copy, make another copy. 80b862204352f1a6028e0bfafd25df1cbca114208bvandebo@chromium.org if (dupInput[i] && multiplier[i] != 0) { 81da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup "); 82da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 83da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 84da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (multiplier[i] == 0) { 85da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(prevColor[i]); 86da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 87da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 88da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (multiplier[i] != 1) { 89da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(multiplier[i]); 90da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" mul "); 91da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 92da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (prevColor[i] != 0) { 93da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(prevColor[i]); 94da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" add "); 95da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 96da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 97da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 98da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (dupInput[i]) { 99da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("exch\n"); 100da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 101da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 102da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 103da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 104da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* Generate Type 4 function code to map t=[0,1) to the passed gradient, 105da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org clamping at the edges of the range. The generated code will be of the form: 106da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (t < 0) { 107da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return colorData[0][r,g,b]; 108da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 109da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (t < info.fColorOffsets[1]) { 110da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return linearinterpolation(colorData[0][r,g,b], 111da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[1][r,g,b]); 112da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 113da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (t < info.fColorOffsets[2]) { 114da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return linearinterpolation(colorData[1][r,g,b], 115da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[2][r,g,b]); 116da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 117da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 118da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org ... } else { 119da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return colorData[info.fColorCount - 1][r,g,b]; 120da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 121da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org ... 122da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 123da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 124da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 125da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void gradientFunctionCode(const SkShader::GradientInfo& info, 126da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString* result) { 127da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org /* We want to linearly interpolate from the previous color to the next. 128da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org Scale the colors from 0..255 to 0..1 and determine the multipliers 129da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for interpolation. 130da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}. 131da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 132da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org static const int kColorComponents = 3; 133316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com typedef SkScalar ColorTuple[kColorComponents]; 134316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount); 135316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com ColorTuple *colorData = colorDataAlloc.get(); 136da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org const SkScalar scale = SkScalarInvert(SkIntToScalar(255)); 137da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for (int i = 0; i < info.fColorCount; i++) { 138da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale); 139da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale); 140da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale); 141da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 142da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 143da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Clamp the initial color. 144da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup 0 le {pop "); 145da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[0][0]); 146da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 147da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[0][1]); 148da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 149da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[0][2]); 150da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" }\n"); 151da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 152da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // The gradient colors. 1538135323f70b38e465761ab3e9817183750e3864dedisonn@google.com int gradients = 0; 154da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for (int i = 1 ; i < info.fColorCount; i++) { 1558135323f70b38e465761ab3e9817183750e3864dedisonn@google.com if (info.fColorOffsets[i] == info.fColorOffsets[i - 1]) { 1568135323f70b38e465761ab3e9817183750e3864dedisonn@google.com continue; 1578135323f70b38e465761ab3e9817183750e3864dedisonn@google.com } 1588135323f70b38e465761ab3e9817183750e3864dedisonn@google.com gradients++; 1598135323f70b38e465761ab3e9817183750e3864dedisonn@google.com 160da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("{dup "); 161da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(info.fColorOffsets[i]); 162da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" le {"); 163da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (info.fColorOffsets[i - 1] != 0) { 164da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(info.fColorOffsets[i - 1]); 165da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" sub\n"); 166da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 167da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 168da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1], 16953648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com colorData[i], colorData[i - 1], result); 170da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("}\n"); 171da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 172da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 173da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Clamp the final color. 174da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("{pop "); 175da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[info.fColorCount - 1][0]); 176da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 177da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[info.fColorCount - 1][1]); 178da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 179da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[info.fColorCount - 1][2]); 180da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1818135323f70b38e465761ab3e9817183750e3864dedisonn@google.com for (int i = 0 ; i < gradients + 1; i++) { 182da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("} ifelse\n"); 183da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 184da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 185da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 186da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */ 187da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void tileModeCode(SkShader::TileMode mode, SkString* result) { 188da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (mode == SkShader::kRepeat_TileMode) { 189da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup truncate sub\n"); // Get the fractional part. 190da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1) 191da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return; 192da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 193da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 194da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (mode == SkShader::kMirror_TileMode) { 195da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Map t mod 2 into [0, 1, 1, 0]. 196da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Code Stack 197da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("abs " // Map negative to positive. 198da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "dup " // t.s t.s 199da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "truncate " // t.s t 200da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "dup " // t.s t t 201da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "cvi " // t.s t T 202da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "2 mod " // t.s t (i mod 2) 203da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "1 eq " // t.s t true|false 204da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "3 1 roll " // true|false t.s t 205da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "sub " // true|false 0.s 206da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "exch " // 0.s true|false 207da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "{1 exch sub} if\n"); // 1 - 0.s|0.s 208da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 209da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 210da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 21183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com/** 21283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * Returns PS function code that applies inverse perspective 21383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * to a x, y point. 21483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * The function assumes that the stack has at least two elements, 21583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * and that the top 2 elements are numeric values. 21683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * After executing this code on a PS stack, the last 2 elements are updated 21783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * while the rest of the stack is preserved intact. 21883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * inversePerspectiveMatrix is the inverse perspective matrix. 21983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com */ 22083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString apply_perspective_to_coordinates( 22183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& inversePerspectiveMatrix) { 22283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com SkString code; 22383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com if (!inversePerspectiveMatrix.hasPerspective()) { 22483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com return code; 22583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com } 22683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 22783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // Perspective matrix should be: 22883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // 1 0 0 22983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // 0 1 0 23083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // p0 p1 p2 23183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 23283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p0 = inversePerspectiveMatrix[SkMatrix::kMPersp0]; 23383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p1 = inversePerspectiveMatrix[SkMatrix::kMPersp1]; 23483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p2 = inversePerspectiveMatrix[SkMatrix::kMPersp2]; 23583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 23683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // y = y / (p2 + p0 x + p1 y) 23783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // x = x / (p2 + p0 x + p1 y) 23883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 23983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // Input on stack: x y 24083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.append(" dup "); // x y y 24183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.appendScalar(p1); // x y y p1 24283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.append(" mul " // x y y*p1 24383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com " 2 index "); // x y y*p1 x 24483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.appendScalar(p0); // x y y p1 x p0 24583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.append(" mul "); // x y y*p1 x*p0 24683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.appendScalar(p2); // x y y p1 x*p0 p2 24783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.append(" add " // x y y*p1 x*p0+p2 24883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "add " // x y y*p1+x*p0+p2 24983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "3 1 roll " // y*p1+x*p0+p2 x y 25083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "2 index " // z x y y*p1+x*p0+p2 25183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "div " // y*p1+x*p0+p2 x y/(y*p1+x*p0+p2) 25283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "3 1 roll " // y/(y*p1+x*p0+p2) y*p1+x*p0+p2 x 25383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "exch " // y/(y*p1+x*p0+p2) x y*p1+x*p0+p2 25483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "div " // y/(y*p1+x*p0+p2) x/(y*p1+x*p0+p2) 25583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "exch\n"); // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2) 25683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com return code; 25783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com} 25883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 25983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString linearCode(const SkShader::GradientInfo& info, 26083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) { 26183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com SkString function("{"); 26283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 26383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com function.append(apply_perspective_to_coordinates(perspectiveRemover)); 26483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 26583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com function.append("pop\n"); // Just ditch the y value. 266da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 267da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 268da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 269da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 270da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 271da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 27283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString radialCode(const SkShader::GradientInfo& info, 27383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) { 274da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString function("{"); 27583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 27683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com function.append(apply_perspective_to_coordinates(perspectiveRemover)); 27783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 278da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Find the distance from the origin. 279da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("dup " // x y y 280da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "mul " // x y^2 281da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "exch " // y^2 x 282da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "dup " // y^2 x x 283da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "mul " // y^2 x^2 284da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "add " // y^2+x^2 285da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "sqrt\n"); // sqrt(y^2+x^2) 286da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 287da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 288da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 289da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 290da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 291da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 292da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 2936219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com/* Conical gradient shader, based on the Canvas spec for radial gradients 294d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient 2956219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com */ 29683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString twoPointConicalCode(const SkShader::GradientInfo& info, 29783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) { 2986219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX; 2996219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY; 3006219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar r0 = info.fRadius[0]; 3016219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar dr = info.fRadius[1] - info.fRadius[0]; 302d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - 3036219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalarMul(dr, dr); 3046219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3056219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // First compute t, if the pixel falls outside the cone, then we'll end 3066219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // with 'false' on the stack, otherwise we'll push 'true' with t below it 3076219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3086219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // We start with a stack of (x y), copy it and then consume one copy in 3096219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // order to calculate b and the other to calculate c. 3106219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkString function("{"); 31183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 31283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com function.append(apply_perspective_to_coordinates(perspectiveRemover)); 31383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 3146219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("2 copy "); 3156219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3166219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr). 3176219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dy); 3186219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul exch "); 3196219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dx); 3206219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul add "); 3216219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(SkScalarMul(r0, dr)); 3226219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add -2 mul dup dup mul\n"); 3236219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3246219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // c = x^2 + y^2 + radius0^2 3256219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("4 2 roll dup mul exch dup mul add "); 3266219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(SkScalarMul(r0, r0)); 3276219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" sub dup 4 1 roll\n"); 3286219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3296219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // Contents of the stack at this point: c, b, b^2, c 3306219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3316219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if a = 0, then we collapse to a simpler linear case 3326219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com if (a == 0) { 3336219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3346219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // t = -c/b 3356219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("pop pop div neg dup "); 3366219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3376219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // compute radius(t) 3386219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dr); 3396219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul "); 3406219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(r0); 3416219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add\n"); 3426219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3436219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if r(t) < 0, then it's outside the cone 344ab2fe82840f37e92e7c45a36cac725c6fd2512c7rileya@google.com function.append("0 lt {pop false} {true} ifelse\n"); 3456219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3466219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com } else { 3476219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3486219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // quadratic case: the Canvas spec wants the largest 3496219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // root t for which radius(t) > 0 350d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 3516219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // compute the discriminant (b^2 - 4ac) 3526219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(SkScalarMul(SkIntToScalar(4), a)); 3536219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul sub dup\n"); 3546219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3556219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if d >= 0, proceed 3566219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("0 ge {\n"); 3576219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3586219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // an intermediate value we'll use to compute the roots: 3596219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // q = -0.5 * (b +/- sqrt(d)) 3606219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("sqrt exch dup 0 lt {exch -1 mul} if"); 3616219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add -0.5 mul dup\n"); 3626219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3636219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // first root = q / a 3646219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(a); 3656219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" div\n"); 3666219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3676219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // second root = c / q 3686219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("3 1 roll div\n"); 3696219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3706219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // put the larger root on top of the stack 3716219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("2 copy gt {exch} if\n"); 3726219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3736219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // compute radius(t) for larger root 3746219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("dup "); 3756219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dr); 3766219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul "); 3776219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(r0); 3786219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add\n"); 3796219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3806219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if r(t) > 0, we have our t, pop off the smaller root and we're done 3816219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" 0 gt {exch pop true}\n"); 3826219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3836219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // otherwise, throw out the larger one and try the smaller root 3846219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("{pop dup\n"); 3856219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dr); 3866219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul "); 3876219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(r0); 3886219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add\n"); 3896219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3906219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if r(t) < 0, push false, otherwise the smaller root is our t 391ab2fe82840f37e92e7c45a36cac725c6fd2512c7rileya@google.com function.append("0 le {pop false} {true} ifelse\n"); 3926219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("} ifelse\n"); 3936219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3946219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // d < 0, clear the stack and push false 395ab2fe82840f37e92e7c45a36cac725c6fd2512c7rileya@google.com function.append("} {pop pop pop false} ifelse\n"); 3966219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com } 3976219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3986219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if the pixel is in the cone, proceed to compute a color 3996219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("{"); 4006219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com tileModeCode(info.fTileMode, &function); 4016219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com gradientFunctionCode(info, &function); 4026219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4036219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // otherwise, just write black 4046219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("} {0 0 0} ifelse }"); 4056219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4066219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com return function; 4076219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com} 4086219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 40983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString sweepCode(const SkShader::GradientInfo& info, 41083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) { 411da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString function("{exch atan 360 div\n"); 412da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 413da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 414da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 415da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 416da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 417da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 418c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malitastatic void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& matrix) { 419c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita SkAutoCanvasRestore acr(canvas, true); 420c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita canvas->concat(matrix); 421c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita canvas->drawBitmap(bm, 0, 0); 422c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita} 423c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita 424421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgclass SkPDFShader::State { 425421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgpublic: 426421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkShader::GradientType fType; 427421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkShader::GradientInfo fInfo; 42893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoFree fColorData; // This provides storage for arrays in fInfo. 429421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkMatrix fCanvasTransform; 430421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkMatrix fShaderTransform; 431421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkIRect fBBox; 432421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 433421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkBitmap fImage; 434421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org uint32_t fPixelGeneration; 435421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkShader::TileMode fImageTileModes[2]; 436421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 43793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org State(const SkShader& shader, const SkMatrix& canvasTransform, 438c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita const SkIRect& bbox, SkScalar rasterScale); 43993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 440421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org bool operator==(const State& b) const; 44193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 44293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFShader::State* CreateAlphaToLuminosityState() const; 44393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFShader::State* CreateOpaqueState() const; 44493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 44593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org bool GradientHasAlpha() const; 44693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 44793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgprivate: 44893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org State(const State& other); 44993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org State operator=(const State& rhs); 45093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org void AllocateGradientInfoStorage(); 451421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}; 452421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 453530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary//////////////////////////////////////////////////////////////////////////////// 454da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 4552e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanarySkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) 4562e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanary : SkPDFDict("Pattern"), fShaderState(state) {} 457da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 458547019e1a671b1b30746e69b9647b201500e1504halcanarySkPDFFunctionShader::~SkPDFFunctionShader() {} 459bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 460530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanarybool SkPDFFunctionShader::equals(const SkPDFShader::State& state) const { 461530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary return state == *fShaderState; 462530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary} 46393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 464530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary//////////////////////////////////////////////////////////////////////////////// 46593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 4662e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanarySkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state) 4672e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanary : fShaderState(state) {} 46893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 469530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanarybool SkPDFAlphaFunctionShader::equals(const SkPDFShader::State& state) const { 470530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary return state == *fShaderState; 471530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary} 472bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 4732e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanarySkPDFAlphaFunctionShader::~SkPDFAlphaFunctionShader() {} 474421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 475530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary//////////////////////////////////////////////////////////////////////////////// 476421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 4772e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanarySkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) 4782e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanary : fShaderState(state) {} 479421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 480530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanarybool SkPDFImageShader::equals(const SkPDFShader::State& state) const { 481530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary return state == *fShaderState; 482530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary} 483fb62b3d423fa34c672df42f47017dbef087d19e9halcanary 484547019e1a671b1b30746e69b9647b201500e1504halcanarySkPDFImageShader::~SkPDFImageShader() {} 485fb62b3d423fa34c672df42f47017dbef087d19e9halcanary 486530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary//////////////////////////////////////////////////////////////////////////////// 487530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary 488530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanarystatic SkPDFObject* get_pdf_shader_by_state( 489792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkPDFCanon* canon, 490792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkScalar dpi, 491bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkAutoTDelete<SkPDFShader::State>* autoState) { 492530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary const SkPDFShader::State& state = **autoState; 493bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary if (state.fType == SkShader::kNone_GradientType && state.fImage.isNull()) { 494da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // TODO(vandebo) This drops SKComposeShader on the floor. We could 495da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // handle compose shader by pulling things up to a layer, drawing with 496da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // the first shader, applying the xfer mode and drawing again with the 497da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // second shader, then applying the layer to the original drawing. 498da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org return NULL; 499530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary } else if (state.fType == SkShader::kNone_GradientType) { 500792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkPDFObject* shader = canon->findImageShader(state); 501792c80f5a7b66e75d42664ccb298f31962c6654chalcanary return shader ? SkRef(shader) 502792c80f5a7b66e75d42664ccb298f31962c6654chalcanary : SkPDFImageShader::Create(canon, dpi, autoState); 503bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary } else if (state.GradientHasAlpha()) { 504792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkPDFObject* shader = canon->findAlphaShader(state); 505530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanary return shader ? SkRef(shader) 506792c80f5a7b66e75d42664ccb298f31962c6654chalcanary : SkPDFAlphaFunctionShader::Create(canon, dpi, autoState); 507421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org } else { 508792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkPDFObject* shader = canon->findFunctionShader(state); 509792c80f5a7b66e75d42664ccb298f31962c6654chalcanary return shader ? SkRef(shader) 510792c80f5a7b66e75d42664ccb298f31962c6654chalcanary : SkPDFFunctionShader::Create(canon, autoState); 511386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org } 51293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 51393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 51493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org// static 515792c80f5a7b66e75d42664ccb298f31962c6654chalcanarySkPDFObject* SkPDFShader::GetPDFShader(SkPDFCanon* canon, 516792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkScalar dpi, 517792c80f5a7b66e75d42664ccb298f31962c6654chalcanary const SkShader& shader, 51893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const SkMatrix& matrix, 519c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita const SkIRect& surfaceBBox, 520c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita SkScalar rasterScale) { 521bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkAutoTDelete<SkPDFShader::State> state( 522c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita SkNEW_ARGS(State, (shader, matrix, surfaceBBox, rasterScale))); 523792c80f5a7b66e75d42664ccb298f31962c6654chalcanary return get_pdf_shader_by_state(canon, dpi, &state); 524da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 525da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 5262b86155b42c2493ff0c558ce105a464769962274halcanarystatic SkPDFDict* get_gradient_resource_dict( 52793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFObject* functionShader, 52893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFObject* gState) { 5292b86155b42c2493ff0c558ce105a464769962274halcanary SkTDArray<SkPDFObject*> patterns; 5302b86155b42c2493ff0c558ce105a464769962274halcanary if (functionShader) { 5312b86155b42c2493ff0c558ce105a464769962274halcanary patterns.push(functionShader); 53293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 5332b86155b42c2493ff0c558ce105a464769962274halcanary SkTDArray<SkPDFObject*> graphicStates; 5342b86155b42c2493ff0c558ce105a464769962274halcanary if (gState) { 5352b86155b42c2493ff0c558ce105a464769962274halcanary graphicStates.push(gState); 53693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 5372b86155b42c2493ff0c558ce105a464769962274halcanary return SkPDFResourceDict::Create(&graphicStates, &patterns, NULL, NULL); 53893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 53993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 54093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgstatic void populate_tiling_pattern_dict(SkPDFDict* pattern, 541547019e1a671b1b30746e69b9647b201500e1504halcanary SkRect& bbox, 542547019e1a671b1b30746e69b9647b201500e1504halcanary SkPDFDict* resources, 543547019e1a671b1b30746e69b9647b201500e1504halcanary const SkMatrix& matrix) { 54493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const int kTiling_PatternType = 1; 54593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const int kColoredTilingPattern_PaintType = 1; 54693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const int kConstantSpacing_TilingType = 1; 54793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 54893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertName("Type", "Pattern"); 54993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertInt("PatternType", kTiling_PatternType); 55093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertInt("PaintType", kColoredTilingPattern_PaintType); 55193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertInt("TilingType", kConstantSpacing_TilingType); 552a25b3371a7209105e6c05f7bbb53d19e2b14498bhalcanary pattern->insertObject("BBox", SkPDFUtils::RectToArray(bbox)); 55393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertScalar("XStep", bbox.width()); 55493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertScalar("YStep", bbox.height()); 555a25b3371a7209105e6c05f7bbb53d19e2b14498bhalcanary pattern->insertObject("Resources", SkRef(resources)); 55693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (!matrix.isIdentity()) { 557a25b3371a7209105e6c05f7bbb53d19e2b14498bhalcanary pattern->insertObject("Matrix", SkPDFUtils::MatrixToArray(matrix)); 55893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 55993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 56093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 56193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 56293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Creates a content stream which fills the pattern P0 across bounds. 56393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * @param gsIndex A graphics state resource index to apply, or <0 if no 56493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * graphics state to apply. 56593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 56693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgstatic SkStream* create_pattern_fill_content(int gsIndex, SkRect& bounds) { 56793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkDynamicMemoryWStream content; 56893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (gsIndex >= 0) { 56993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFUtils::ApplyGraphicState(gsIndex, &content); 57093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 57193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFUtils::ApplyPattern(0, &content); 57293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFUtils::AppendRectangle(bounds, &content); 57393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPath::kEvenOdd_FillType, 57493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org &content); 57593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 57693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return content.detachAsStream(); 57793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 57893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 57993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 58093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Creates a ExtGState with the SMask set to the luminosityShader in 58193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * luminosity mode. The shader pattern extends to the bbox. 58293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 583be27a118c277af23377d38e9b3bfd3fcc276114fhalcanarystatic SkPDFObject* create_smask_graphic_state( 584792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkPDFCanon* canon, SkScalar dpi, const SkPDFShader::State& state) { 58593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkRect bbox; 586bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary bbox.set(state.fBBox); 58793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 588bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkAutoTDelete<SkPDFShader::State> alphaToLuminosityState( 589bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary state.CreateAlphaToLuminosityState()); 590bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkAutoTUnref<SkPDFObject> luminosityShader( 591792c80f5a7b66e75d42664ccb298f31962c6654chalcanary get_pdf_shader_by_state(canon, dpi, &alphaToLuminosityState)); 59293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 593a1193e4b0e34a7e4e1bd33e9708d7341679f8321scroggo SkAutoTDelete<SkStream> alphaStream(create_pattern_fill_content(-1, bbox)); 59493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 5952b86155b42c2493ff0c558ce105a464769962274halcanary SkAutoTUnref<SkPDFDict> 59693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org resources(get_gradient_resource_dict(luminosityShader, NULL)); 59793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 59893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTUnref<SkPDFFormXObject> alphaMask( 59993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org new SkPDFFormXObject(alphaStream.get(), bbox, resources.get())); 60093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 60193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return SkPDFGraphicState::GetSMaskGraphicState( 60293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org alphaMask.get(), false, 60393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFGraphicState::kLuminosity_SMaskMode); 60493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 60593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 606530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanarySkPDFAlphaFunctionShader* SkPDFAlphaFunctionShader::Create( 607792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkPDFCanon* canon, 608792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkScalar dpi, 609bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkAutoTDelete<SkPDFShader::State>* autoState) { 610bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary const SkPDFShader::State& state = **autoState; 61193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkRect bbox; 612bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary bbox.set(state.fBBox); 61393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 614bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkAutoTDelete<SkPDFShader::State> opaqueState(state.CreateOpaqueState()); 615bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 616547019e1a671b1b30746e69b9647b201500e1504halcanary SkAutoTUnref<SkPDFObject> colorShader( 617547019e1a671b1b30746e69b9647b201500e1504halcanary get_pdf_shader_by_state(canon, dpi, &opaqueState)); 618bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary if (!colorShader) { 619bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return NULL; 620bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary } 62193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 62293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org // Create resource dict with alpha graphics state as G0 and 62393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org // pattern shader as P0, then write content stream. 624be27a118c277af23377d38e9b3bfd3fcc276114fhalcanary SkAutoTUnref<SkPDFObject> alphaGs( 625792c80f5a7b66e75d42664ccb298f31962c6654chalcanary create_smask_graphic_state(canon, dpi, state)); 626bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 627bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkPDFAlphaFunctionShader* alphaFunctionShader = 6282e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanary SkNEW_ARGS(SkPDFAlphaFunctionShader, (autoState->detach())); 629bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 6302b86155b42c2493ff0c558ce105a464769962274halcanary SkAutoTUnref<SkPDFDict> resourceDict( 631547019e1a671b1b30746e69b9647b201500e1504halcanary get_gradient_resource_dict(colorShader.get(), alphaGs.get())); 63293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 633a1193e4b0e34a7e4e1bd33e9708d7341679f8321scroggo SkAutoTDelete<SkStream> colorStream( 63493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org create_pattern_fill_content(0, bbox)); 635bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary alphaFunctionShader->setData(colorStream.get()); 63693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 637547019e1a671b1b30746e69b9647b201500e1504halcanary populate_tiling_pattern_dict(alphaFunctionShader, bbox, resourceDict.get(), 63893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkMatrix::I()); 639792c80f5a7b66e75d42664ccb298f31962c6654chalcanary canon->addAlphaShader(alphaFunctionShader); 640bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return alphaFunctionShader; 64193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 64293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 64383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com// Finds affine and persp such that in = affine * persp. 64483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com// but it returns the inverse of perspective matrix. 64583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic bool split_perspective(const SkMatrix in, SkMatrix* affine, 64683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com SkMatrix* perspectiveInverse) { 64783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p2 = in[SkMatrix::kMPersp2]; 64883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 64983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com if (SkScalarNearlyZero(p2)) { 65083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com return false; 65183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com } 65283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 65383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar zero = SkIntToScalar(0); 65483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar one = SkIntToScalar(1); 65583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 65683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar sx = in[SkMatrix::kMScaleX]; 65783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar kx = in[SkMatrix::kMSkewX]; 65883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar tx = in[SkMatrix::kMTransX]; 65983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar ky = in[SkMatrix::kMSkewY]; 66083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar sy = in[SkMatrix::kMScaleY]; 66183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar ty = in[SkMatrix::kMTransY]; 66283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p0 = in[SkMatrix::kMPersp0]; 66383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p1 = in[SkMatrix::kMPersp1]; 66483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 66583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // Perspective matrix would be: 66683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // 1 0 0 66783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // 0 1 0 66883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // p0 p1 p2 66983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // But we need the inverse of persp. 67083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com perspectiveInverse->setAll(one, zero, zero, 67183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com zero, one, zero, 67283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com -p0/p2, -p1/p2, 1/p2); 67383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 67483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com affine->setAll(sx - p0 * tx / p2, kx - p1 * tx / p2, tx / p2, 67583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com ky - p0 * ty / p2, sy - p1 * ty / p2, ty / p2, 67683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com zero, zero, one); 67783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 67883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com return true; 67983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com} 68083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 681bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanarynamespace { 682bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanarySkPDFObject* create_range_object() { 683bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkPDFArray* range = SkNEW(SkPDFArray); 684bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary range->reserve(6); 685bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary range->appendInt(0); 686bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary range->appendInt(1); 687bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary range->appendInt(0); 688bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary range->appendInt(1); 689bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary range->appendInt(0); 690bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary range->appendInt(1); 691bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return range; 692bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary} 693bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 694bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanarytemplate <typename T> void unref(T* ptr) { ptr->unref();} 695bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary} // namespace 696bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 697bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanarySK_DECLARE_STATIC_LAZY_PTR(SkPDFObject, rangeObject, 698bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary create_range_object, unref<SkPDFObject>); 699bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 700bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanarystatic SkPDFStream* make_ps_function(const SkString& psCode, 701bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkPDFArray* domain) { 702bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkAutoDataUnref funcData( 703bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkData::NewWithCopy(psCode.c_str(), psCode.size())); 704bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkPDFStream* result = SkNEW_ARGS(SkPDFStream, (funcData.get())); 705bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary result->insertInt("FunctionType", 4); 706a25b3371a7209105e6c05f7bbb53d19e2b14498bhalcanary result->insertObject("Domain", SkRef(domain)); 707a25b3371a7209105e6c05f7bbb53d19e2b14498bhalcanary result->insertObject("Range", SkRef(rangeObject.get())); 708bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return result; 709bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary} 710bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 711530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanarySkPDFFunctionShader* SkPDFFunctionShader::Create( 712792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkPDFCanon* canon, SkAutoTDelete<SkPDFShader::State>* autoState) { 713bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary const SkPDFShader::State& state = **autoState; 714bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 71583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com SkString (*codeFunction)(const SkShader::GradientInfo& info, 71683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) = NULL; 717da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkPoint transformPoints[2]; 718da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 719da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Depending on the type of the gradient, we want to transform the 720da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // coordinate space in different ways. 721bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary const SkShader::GradientInfo* info = &state.fInfo; 722da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[0] = info->fPoint[0]; 723da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = info->fPoint[1]; 724bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary switch (state.fType) { 725da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kLinear_GradientType: 726da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &linearCode; 727da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 728da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kRadial_GradientType: 729da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = transformPoints[0]; 730da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1].fX += info->fRadius[0]; 731da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &radialCode; 732da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 7336219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com case SkShader::kConical_GradientType: { 7346219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com transformPoints[1] = transformPoints[0]; 7356219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com transformPoints[1].fX += SK_Scalar1; 7366219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com codeFunction = &twoPointConicalCode; 7376219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com break; 7386219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com } 739da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kSweep_GradientType: 740da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = transformPoints[0]; 741c39c8674c94dba8b1ffe938cd99c825320cc1475vandebo@chromium.org transformPoints[1].fX += SK_Scalar1; 742da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &sweepCode; 743da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 744da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kColor_GradientType: 745da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kNone_GradientType: 746020798af6780ba29156f4daec87c29ae9e4f4a12vandebo@chromium.org default: 747bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return NULL; 748da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 749da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 750da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Move any scaling (assuming a unit gradient) or translation 751da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // (and rotation for linear gradient), of the final gradient from 752da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // info->fPoints to the matrix (updating bbox appropriately). Now 753da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // the gradient can be drawn on on the unit segment. 754da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix mapperMatrix; 755da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org unitToPointsMatrix(transformPoints, &mapperMatrix); 75683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 757bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkMatrix finalMatrix = state.fCanvasTransform; 758bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary finalMatrix.preConcat(state.fShaderTransform); 759ace2269edfed9dfd3097597f1698921aaddf80a1commit-bot@chromium.org finalMatrix.preConcat(mapperMatrix); 760ace2269edfed9dfd3097597f1698921aaddf80a1commit-bot@chromium.org 76183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // Preserves as much as posible in the final matrix, and only removes 76283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // the perspective. The inverse of the perspective is stored in 76383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // perspectiveInverseOnly matrix and has 3 useful numbers 76483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // (p0, p1, p2), while everything else is either 0 or 1. 76583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // In this way the shader will handle it eficiently, with minimal code. 76683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com SkMatrix perspectiveInverseOnly = SkMatrix::I(); 76783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com if (finalMatrix.hasPerspective()) { 76883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com if (!split_perspective(finalMatrix, 76983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com &finalMatrix, &perspectiveInverseOnly)) { 770bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return NULL; 77183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com } 77283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com } 77383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 774da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRect bbox; 775bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary bbox.set(state.fBBox); 7767b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita if (!inverse_transform_bbox(finalMatrix, &bbox)) { 777bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return NULL; 778386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org } 779da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 780d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkAutoTUnref<SkPDFArray> domain(new SkPDFArray); 781da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org domain->reserve(4); 782c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fLeft); 783c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fRight); 784c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fTop); 785c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fBottom); 786da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 787da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString functionCode; 788fb62b3d423fa34c672df42f47017dbef087d19e9halcanary // The two point radial gradient further references 789bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary // state.fInfo 790da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // in translating from x, y coordinates to the t parameter. So, we have 791da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // to transform the points and radii according to the calculated matrix. 79271a6cbfc585959738dc0b375603696ca7f60605freed if (state.fType == SkShader::kConical_GradientType) { 793da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkShader::GradientInfo twoPointRadialInfo = *info; 794da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix inverseMapperMatrix; 795b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org if (!mapperMatrix.invert(&inverseMapperMatrix)) { 796bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return NULL; 797b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org } 798da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); 799da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org twoPointRadialInfo.fRadius[0] = 800da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverseMapperMatrix.mapRadius(info->fRadius[0]); 801da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org twoPointRadialInfo.fRadius[1] = 802da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverseMapperMatrix.mapRadius(info->fRadius[1]); 80383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly); 804da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 80583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com functionCode = codeFunction(*info, perspectiveInverseOnly); 806da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 807da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 808d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict); 809c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com pdfShader->insertInt("ShadingType", 1); 810c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com pdfShader->insertName("ColorSpace", "DeviceRGB"); 811a25b3371a7209105e6c05f7bbb53d19e2b14498bhalcanary pdfShader->insertObject("Domain", SkRef(domain.get())); 812d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org 813f5b17fbd9406ea276d62886a072872dbd48ca58ahalcanary SkAutoTUnref<SkPDFStream> function( 814f5b17fbd9406ea276d62886a072872dbd48ca58ahalcanary make_ps_function(functionCode, domain.get())); 815a25b3371a7209105e6c05f7bbb53d19e2b14498bhalcanary pdfShader->insertObjRef("Function", function.detach()); 816bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 817bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkPDFFunctionShader* pdfFunctionShader = 8182e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanary SkNEW_ARGS(SkPDFFunctionShader, (autoState->detach())); 819bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 820bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary pdfFunctionShader->insertInt("PatternType", 2); 821a25b3371a7209105e6c05f7bbb53d19e2b14498bhalcanary pdfFunctionShader->insertObject("Matrix", 822a25b3371a7209105e6c05f7bbb53d19e2b14498bhalcanary SkPDFUtils::MatrixToArray(finalMatrix)); 823a25b3371a7209105e6c05f7bbb53d19e2b14498bhalcanary pdfFunctionShader->insertObject("Shading", pdfShader.detach()); 824bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 825792c80f5a7b66e75d42664ccb298f31962c6654chalcanary canon->addFunctionShader(pdfFunctionShader); 826bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return pdfFunctionShader; 827da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 828da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 829530ea8e24bc88f2d7973c35a703f18c1dafb56dchalcanarySkPDFImageShader* SkPDFImageShader::Create( 830792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkPDFCanon* canon, 831792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkScalar dpi, 832bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkAutoTDelete<SkPDFShader::State>* autoState) { 833bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary const SkPDFShader::State& state = **autoState; 834bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 835bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary state.fImage.lockPixels(); 836da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 837e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // The image shader pattern cell will be drawn into a separate device 838e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // in pattern cell space (no scaling on the bitmap, though there may be 839e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // translations so that all content is in the device, coordinates > 0). 840e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 841e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // Map clip bounds to shader space to ensure the device is large enough 842e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // to handle fake clamping. 843bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkMatrix finalMatrix = state.fCanvasTransform; 844bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary finalMatrix.preConcat(state.fShaderTransform); 845e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkRect deviceBounds; 846bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary deviceBounds.set(state.fBBox); 8477b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita if (!inverse_transform_bbox(finalMatrix, &deviceBounds)) { 848bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return NULL; 849386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org } 850da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 851bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary const SkBitmap* image = &state.fImage; 852e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkRect bitmapBounds; 853e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org image->getBounds(&bitmapBounds); 854e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 855e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // For tiling modes, the bounds should be extended to include the bitmap, 856e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // otherwise the bitmap gets clipped out and the shader is empty and awful. 857e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // For clamp modes, we're only interested in the clip region, whether 858e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // or not the main bitmap is in it. 859e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkShader::TileMode tileModes[2]; 860bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary tileModes[0] = state.fImageTileModes[0]; 861bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary tileModes[1] = state.fImageTileModes[1]; 862e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (tileModes[0] != SkShader::kClamp_TileMode || 863e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org tileModes[1] != SkShader::kClamp_TileMode) { 864e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org deviceBounds.join(bitmapBounds); 865e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org } 866e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 867e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()), 868e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com SkScalarRoundToInt(deviceBounds.height())); 869a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary SkAutoTUnref<SkPDFDevice> patternDevice( 870792c80f5a7b66e75d42664ccb298f31962c6654chalcanary SkPDFDevice::CreateUnflipped(size, dpi, canon)); 871a1f1ee98a1f6d0770f6243270ca2f0e6c92efabahalcanary SkCanvas canvas(patternDevice.get()); 872da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 873e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkRect patternBBox; 874e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org image->getBounds(&patternBBox); 875da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 876e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // Translate the canvas so that the bitmap origin is at (0, 0). 877e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org canvas.translate(-deviceBounds.left(), -deviceBounds.top()); 878e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org patternBBox.offset(-deviceBounds.left(), -deviceBounds.top()); 879e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // Undo the translation in the final matrix 880e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org finalMatrix.preTranslate(deviceBounds.left(), deviceBounds.top()); 881e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 882e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // If the bitmap is out of bounds (i.e. clamp mode where we only see the 883e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // stretched sides), canvas will clip this out and the extraneous data 884e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // won't be saved to the PDF. 885da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmap(*image, 0, 0); 886e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 887e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkScalar width = SkIntToScalar(image->width()); 888e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkScalar height = SkIntToScalar(image->height()); 889da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 890da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Tiling is implied. First we handle mirroring. 891da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode) { 892da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix xMirror; 893da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org xMirror.setScale(-1, 1); 894da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org xMirror.postTranslate(2 * width, 0); 895c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, *image, xMirror); 896da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org patternBBox.fRight += width; 897da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 898da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kMirror_TileMode) { 899da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix yMirror; 900663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org yMirror.setScale(SK_Scalar1, -SK_Scalar1); 901da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org yMirror.postTranslate(0, 2 * height); 902c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, *image, yMirror); 903da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org patternBBox.fBottom += height; 904da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 905da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode && 906da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModes[1] == SkShader::kMirror_TileMode) { 907da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix mirror; 908da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org mirror.setScale(-1, -1); 909da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org mirror.postTranslate(2 * width, 2 * height); 910c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, *image, mirror); 911da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 912da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 913da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Then handle Clamping, which requires expanding the pattern canvas to 914da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // cover the entire surfaceBBox. 915da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 916da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // If both x and y are in clamp mode, we start by filling in the corners. 917da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // (Which are just a rectangles of the corner colors.) 918da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kClamp_TileMode && 919da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModes[1] == SkShader::kClamp_TileMode) { 920da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkPaint paint; 921da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRect rect; 922e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org rect = SkRect::MakeLTRB(deviceBounds.left(), deviceBounds.top(), 0, 0); 923da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 924da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org paint.setColor(image->getColor(0, 0)); 925da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 926da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 927da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 928e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org rect = SkRect::MakeLTRB(width, deviceBounds.top(), 929e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org deviceBounds.right(), 0); 930da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 93154ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org paint.setColor(image->getColor(image->width() - 1, 0)); 932da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 933da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 934da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 935e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org rect = SkRect::MakeLTRB(width, height, 936e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org deviceBounds.right(), deviceBounds.bottom()); 937da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 93854ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org paint.setColor(image->getColor(image->width() - 1, 93954ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org image->height() - 1)); 940da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 941da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 942da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 943e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org rect = SkRect::MakeLTRB(deviceBounds.left(), height, 944e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 0, deviceBounds.bottom()); 945da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 94654ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org paint.setColor(image->getColor(0, image->height() - 1)); 947da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 948da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 949da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 950da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 951da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Then expand the left, right, top, then bottom. 952da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kClamp_TileMode) { 95354ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height()); 954e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (deviceBounds.left() < 0) { 955da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap left; 956da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&left, subset)); 957da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 958da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix leftMatrix; 959e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org leftMatrix.setScale(-deviceBounds.left(), 1); 960e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org leftMatrix.postTranslate(deviceBounds.left(), 0); 961c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, left, leftMatrix); 962da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 963da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kMirror_TileMode) { 964663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org leftMatrix.postScale(SK_Scalar1, -SK_Scalar1); 965da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org leftMatrix.postTranslate(0, 2 * height); 966c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, left, leftMatrix); 967da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 968be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org patternBBox.fLeft = 0; 969da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 970da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 971e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (deviceBounds.right() > width) { 972da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap right; 97354ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org subset.offset(image->width() - 1, 0); 974da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&right, subset)); 975da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 976da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix rightMatrix; 977e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org rightMatrix.setScale(deviceBounds.right() - width, 1); 978da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rightMatrix.postTranslate(width, 0); 979c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, right, rightMatrix); 980da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 981da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kMirror_TileMode) { 982663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org rightMatrix.postScale(SK_Scalar1, -SK_Scalar1); 983da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rightMatrix.postTranslate(0, 2 * height); 984c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, right, rightMatrix); 985da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 986e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org patternBBox.fRight = deviceBounds.width(); 987da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 988da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 989da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 990da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kClamp_TileMode) { 99154ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1); 992e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (deviceBounds.top() < 0) { 993da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap top; 994da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&top, subset)); 995da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 996da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix topMatrix; 997e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org topMatrix.setScale(SK_Scalar1, -deviceBounds.top()); 998e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org topMatrix.postTranslate(0, deviceBounds.top()); 999c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, top, topMatrix); 1000da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1001da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode) { 1002da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org topMatrix.postScale(-1, 1); 1003da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org topMatrix.postTranslate(2 * width, 0); 1004c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, top, topMatrix); 1005da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1006be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org patternBBox.fTop = 0; 1007da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1008da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1009e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (deviceBounds.bottom() > height) { 1010da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap bottom; 101154ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org subset.offset(0, image->height() - 1); 1012da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&bottom, subset)); 1013da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1014da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix bottomMatrix; 1015e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height); 1016da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bottomMatrix.postTranslate(0, height); 1017c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, bottom, bottomMatrix); 1018da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1019da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode) { 1020da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bottomMatrix.postScale(-1, 1); 1021da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bottomMatrix.postTranslate(2 * width, 0); 1022c54d8db4d169ea5f2af2a9a2349df007bd428475Florin Malita drawBitmapMatrix(&canvas, bottom, bottomMatrix); 1023da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1024e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org patternBBox.fBottom = deviceBounds.height(); 1025da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1026da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1027da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1028da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Put the canvas into the pattern stream (fContent). 1029334fcbc167237f02058cb508cb5f51b718141461halcanary SkAutoTDelete<SkStreamAsset> content(patternDevice->content()); 1030bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 1031bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary SkPDFImageShader* imageShader = 10322e3f9d8a9309686eeb4c76ccfde5800da87a68b3halcanary SkNEW_ARGS(SkPDFImageShader, (autoState->detach())); 1033bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary imageShader->setData(content.get()); 1034bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary 10352b86155b42c2493ff0c558ce105a464769962274halcanary SkAutoTUnref<SkPDFDict> resourceDict( 10366d622703e578eddc64ab4e3340d0ab0033268799halcanary patternDevice->createResourceDict()); 1037792c80f5a7b66e75d42664ccb298f31962c6654chalcanary populate_tiling_pattern_dict(imageShader, patternBBox, 10386d622703e578eddc64ab4e3340d0ab0033268799halcanary resourceDict.get(), finalMatrix); 1039da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1040bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary imageShader->fShaderState->fImage.unlockPixels(); 1041da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1042792c80f5a7b66e75d42664ccb298f31962c6654chalcanary canon->addImageShader(imageShader); 1043bc59ac6b12bbded2117fe3aa9643b2d138e5dddahalcanary return imageShader; 1044da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 1045da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1046da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgbool SkPDFShader::State::operator==(const SkPDFShader::State& b) const { 1047da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fType != b.fType || 1048da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fCanvasTransform != b.fCanvasTransform || 1049da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fShaderTransform != b.fShaderTransform || 1050da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fBBox != b.fBBox) { 1051da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1052da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1053da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1054da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fType == SkShader::kNone_GradientType) { 1055da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fPixelGeneration != b.fPixelGeneration || 1056da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fPixelGeneration == 0 || 1057da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fImageTileModes[0] != b.fImageTileModes[0] || 1058da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fImageTileModes[1] != b.fImageTileModes[1]) { 1059da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1060da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1061da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 1062da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fColorCount != b.fInfo.fColorCount || 1063da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org memcmp(fInfo.fColors, b.fInfo.fColors, 1064da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org sizeof(SkColor) * fInfo.fColorCount) != 0 || 1065da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org memcmp(fInfo.fColorOffsets, b.fInfo.fColorOffsets, 1066da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org sizeof(SkScalar) * fInfo.fColorCount) != 0 || 1067da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fPoint[0] != b.fInfo.fPoint[0] || 1068da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fTileMode != b.fInfo.fTileMode) { 1069da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1070da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1071da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1072da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org switch (fType) { 1073da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kLinear_GradientType: 1074da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fPoint[1] != b.fInfo.fPoint[1]) { 1075da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1076da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1077da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 1078da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kRadial_GradientType: 1079da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fRadius[0] != b.fInfo.fRadius[0]) { 1080da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1081da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1082da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 10834908533aef9830dc1c18552c305ed6ccb286f4f2reed@google.com case SkShader::kConical_GradientType: 1084da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fPoint[1] != b.fInfo.fPoint[1] || 1085da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fRadius[0] != b.fInfo.fRadius[0] || 1086da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fRadius[1] != b.fInfo.fRadius[1]) { 1087da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1088da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1089da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 1090da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kSweep_GradientType: 1091da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kNone_GradientType: 1092da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kColor_GradientType: 1093da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 1094da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1095da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1096da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return true; 1097da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 1098da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1099c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalitaSkPDFShader::State::State(const SkShader& shader, const SkMatrix& canvasTransform, 1100c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita const SkIRect& bbox, SkScalar rasterScale) 1101da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org : fCanvasTransform(canvasTransform), 1102e1bc274295ec57cb3d3f01aaa8abff3b49c76c73vandebo@chromium.org fBBox(bbox), 1103e1bc274295ec57cb3d3f01aaa8abff3b49c76c73vandebo@chromium.org fPixelGeneration(0) { 1104da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fColorCount = 0; 1105da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fColors = NULL; 1106da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fColorOffsets = NULL; 1107f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com fShaderTransform = shader.getLocalMatrix(); 1108e1bc274295ec57cb3d3f01aaa8abff3b49c76c73vandebo@chromium.org fImageTileModes[0] = fImageTileModes[1] = SkShader::kClamp_TileMode; 1109da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1110da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fType = shader.asAGradient(&fInfo); 1111da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1112da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fType == SkShader::kNone_GradientType) { 1113da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkShader::BitmapType bitmapType; 1114da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix matrix; 111591f319c5dc4493384f0a52aaeef3dcc311ef6ed0rileya@google.com bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes); 1116da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (bitmapType != SkShader::kDefault_BitmapType) { 1117c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita // Generic fallback for unsupported shaders: 1118c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita // * allocate a bbox-sized bitmap 1119c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita // * shade the whole area 1120c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita // * use the result as a bitmap shader 1121c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita 11227b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita // bbox is in device space. While that's exactly what we want for sizing our bitmap, 11237b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita // we need to map it into shader space for adjustments (to match 11247b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita // SkPDFImageShader::Create's behavior). 11257b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita SkRect shaderRect = SkRect::Make(bbox); 11267b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita if (!inverse_transform_bbox(canvasTransform, &shaderRect)) { 11277b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita fImage.reset(); 11287b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita return; 11297b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita } 11307b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita 1131c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita // Clamp the bitmap size to about 1M pixels 1132c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita static const SkScalar kMaxBitmapArea = 1024 * 1024; 1133c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita SkScalar bitmapArea = rasterScale * bbox.width() * rasterScale * bbox.height(); 1134c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita if (bitmapArea > kMaxBitmapArea) { 113580ea19ca4bdd68c1493666a5fe7e4ce9d43ded8breed rasterScale *= SkScalarSqrt(kMaxBitmapArea / bitmapArea); 1136c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita } 1137c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita 1138c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita SkISize size = SkISize::Make(SkScalarRoundToInt(rasterScale * bbox.width()), 1139c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita SkScalarRoundToInt(rasterScale * bbox.height())); 11407b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita SkSize scale = SkSize::Make(SkIntToScalar(size.width()) / shaderRect.width(), 11417b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita SkIntToScalar(size.height()) / shaderRect.height()); 1142c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita 1143c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita fImage.allocN32Pixels(size.width(), size.height()); 1144c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita fImage.eraseColor(SK_ColorTRANSPARENT); 1145c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita 1146c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita SkPaint p; 1147c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita p.setShader(const_cast<SkShader*>(&shader)); 1148c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita 1149c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita SkCanvas canvas(fImage); 1150c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita canvas.scale(scale.width(), scale.height()); 11517b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita canvas.translate(-shaderRect.x(), -shaderRect.y()); 1152c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita canvas.drawPaint(p); 1153c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita 11547b4d4c7a4668f771641aaed88b83d22d5efe6873fmalita fShaderTransform.setTranslate(shaderRect.x(), shaderRect.y()); 1155c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita fShaderTransform.preScale(1 / scale.width(), 1 / scale.height()); 1156c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita } else { 1157c3796c7a74e103d9b367ad9449fcdacfa20d83e1fmalita SkASSERT(matrix.isIdentity()); 1158da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1159da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fPixelGeneration = fImage.getGenerationID(); 1160da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 116193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org AllocateGradientInfoStorage(); 1162da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org shader.asAGradient(&fInfo); 1163da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1164da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 116593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 116693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgSkPDFShader::State::State(const SkPDFShader::State& other) 116793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org : fType(other.fType), 116893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fCanvasTransform(other.fCanvasTransform), 116993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fShaderTransform(other.fShaderTransform), 117093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fBBox(other.fBBox) 117193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org{ 117293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org // Only gradients supported for now, since that is all that is used. 117393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org // If needed, image state copy constructor can be added here later. 117493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkASSERT(fType != SkShader::kNone_GradientType); 117593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 117693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (fType != SkShader::kNone_GradientType) { 117793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo = other.fInfo; 117893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 117993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org AllocateGradientInfoStorage(); 118093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org for (int i = 0; i < fInfo.fColorCount; i++) { 118193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo.fColors[i] = other.fInfo.fColors[i]; 118293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo.fColorOffsets[i] = other.fInfo.fColorOffsets[i]; 118393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 118493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 118593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 118693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 118793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 118893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Create a copy of this gradient state with alpha assigned to RGB luminousity. 118993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Only valid for gradient states. 119093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 119193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgSkPDFShader::State* SkPDFShader::State::CreateAlphaToLuminosityState() const { 119293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkASSERT(fType != SkShader::kNone_GradientType); 119393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 119493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFShader::State* newState = new SkPDFShader::State(*this); 119593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 119693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org for (int i = 0; i < fInfo.fColorCount; i++) { 119793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAlpha alpha = SkColorGetA(fInfo.fColors[i]); 119893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org newState->fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha); 119993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 120093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 120193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return newState; 120293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 120393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 120493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 120593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Create a copy of this gradient state with alpha set to fully opaque 120693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Only valid for gradient states. 120793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 120893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgSkPDFShader::State* SkPDFShader::State::CreateOpaqueState() const { 120993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkASSERT(fType != SkShader::kNone_GradientType); 121093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 121193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFShader::State* newState = new SkPDFShader::State(*this); 121293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org for (int i = 0; i < fInfo.fColorCount; i++) { 121393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org newState->fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i], 121493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SK_AlphaOPAQUE); 121593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 121693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 121793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return newState; 121893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 121993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 122093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 122193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Returns true if state is a gradient and the gradient has alpha. 122293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 122393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgbool SkPDFShader::State::GradientHasAlpha() const { 122493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (fType == SkShader::kNone_GradientType) { 122593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return false; 122693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 122793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 122893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org for (int i = 0; i < fInfo.fColorCount; i++) { 122993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAlpha alpha = SkColorGetA(fInfo.fColors[i]); 123093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (alpha != SK_AlphaOPAQUE) { 123193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return true; 123293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 123393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 123493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return false; 123593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 123693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 123793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgvoid SkPDFShader::State::AllocateGradientInfoStorage() { 123893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fColorData.set(sk_malloc_throw( 123993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); 124093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); 124193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo.fColorOffsets = 124293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); 124393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 1244