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" 13da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkPDFCatalog.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 "SkThread.h" 2393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org#include "SkTSet.h" 24da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkTypes.h" 25da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 26e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.orgstatic bool inverseTransformBBox(const SkMatrix& matrix, SkRect* bbox) { 27da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix inverse; 28b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org if (!matrix.invert(&inverse)) { 29386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return false; 30b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org } 31da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverse.mapRect(bbox); 32386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return true; 33da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 34da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 35da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) { 36da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkVector vec = pts[1] - pts[0]; 37da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar mag = vec.length(); 38da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar inv = mag ? SkScalarInvert(mag) : 0; 39da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 40da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org vec.scale(inv); 41da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org matrix->setSinCos(vec.fY, vec.fX); 42da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org matrix->preScale(mag, mag); 43ace2269edfed9dfd3097597f1698921aaddf80a1commit-bot@chromium.org matrix->postTranslate(pts[0].fX, pts[0].fY); 44da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 45da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 46da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* Assumes t + startOffset is on the stack and does a linear interpolation on t 47da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org between startOffset and endOffset from prevColor to curColor (for each color 4853648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com component), leaving the result in component order on the stack. It assumes 4953648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com there are always 3 components per color. 50da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param range endOffset - startOffset 51da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param curColor[components] The current color components. 52da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param prevColor[components] The previous color components. 53da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param result The result ps function. 54da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 55da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void interpolateColorCode(SkScalar range, SkScalar* curColor, 5653648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com SkScalar* prevColor, SkString* result) { 578135323f70b38e465761ab3e9817183750e3864dedisonn@google.com SkASSERT(range != SkIntToScalar(0)); 5853648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com static const int kColorComponents = 3; 5953648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com 60da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Figure out how to scale each color component. 6153648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com SkScalar multiplier[kColorComponents]; 6253648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com for (int i = 0; i < kColorComponents; i++) { 63da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org multiplier[i] = SkScalarDiv(curColor[i] - prevColor[i], range); 64da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 65da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 66da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Calculate when we no longer need to keep a copy of the input parameter t. 67da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // If the last component to use t is i, then dupInput[0..i - 1] = true 68da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // and dupInput[i .. components] = false. 6953648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com bool dupInput[kColorComponents]; 7053648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com dupInput[kColorComponents - 1] = false; 7153648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com for (int i = kColorComponents - 2; i >= 0; i--) { 72da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0; 73da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 74da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 75da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!dupInput[0] && multiplier[0] == 0) { 76da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("pop "); 77da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 78da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 7953648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com for (int i = 0; i < kColorComponents; i++) { 80b862204352f1a6028e0bfafd25df1cbca114208bvandebo@chromium.org // If the next components needs t and this component will consume a 81b862204352f1a6028e0bfafd25df1cbca114208bvandebo@chromium.org // copy, make another copy. 82b862204352f1a6028e0bfafd25df1cbca114208bvandebo@chromium.org if (dupInput[i] && multiplier[i] != 0) { 83da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup "); 84da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 85da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 86da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (multiplier[i] == 0) { 87da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(prevColor[i]); 88da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 89da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 90da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (multiplier[i] != 1) { 91da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(multiplier[i]); 92da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" mul "); 93da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 94da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (prevColor[i] != 0) { 95da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(prevColor[i]); 96da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" add "); 97da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 98da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 99da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 100da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (dupInput[i]) { 101da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("exch\n"); 102da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 103da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 104da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 105da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 106da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* Generate Type 4 function code to map t=[0,1) to the passed gradient, 107da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org clamping at the edges of the range. The generated code will be of the form: 108da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (t < 0) { 109da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return colorData[0][r,g,b]; 110da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 111da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (t < info.fColorOffsets[1]) { 112da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return linearinterpolation(colorData[0][r,g,b], 113da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[1][r,g,b]); 114da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 115da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (t < info.fColorOffsets[2]) { 116da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return linearinterpolation(colorData[1][r,g,b], 117da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[2][r,g,b]); 118da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 119da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 120da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org ... } else { 121da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return colorData[info.fColorCount - 1][r,g,b]; 122da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 123da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org ... 124da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 125da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 126da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 127da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void gradientFunctionCode(const SkShader::GradientInfo& info, 128da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString* result) { 129da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org /* We want to linearly interpolate from the previous color to the next. 130da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org Scale the colors from 0..255 to 0..1 and determine the multipliers 131da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for interpolation. 132da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}. 133da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 134da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org static const int kColorComponents = 3; 135316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com typedef SkScalar ColorTuple[kColorComponents]; 136316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount); 137316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com ColorTuple *colorData = colorDataAlloc.get(); 138da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org const SkScalar scale = SkScalarInvert(SkIntToScalar(255)); 139da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for (int i = 0; i < info.fColorCount; i++) { 140da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale); 141da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale); 142da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale); 143da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 144da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 145da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Clamp the initial color. 146da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup 0 le {pop "); 147da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[0][0]); 148da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 149da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[0][1]); 150da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 151da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[0][2]); 152da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" }\n"); 153da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 154da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // The gradient colors. 1558135323f70b38e465761ab3e9817183750e3864dedisonn@google.com int gradients = 0; 156da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for (int i = 1 ; i < info.fColorCount; i++) { 1578135323f70b38e465761ab3e9817183750e3864dedisonn@google.com if (info.fColorOffsets[i] == info.fColorOffsets[i - 1]) { 1588135323f70b38e465761ab3e9817183750e3864dedisonn@google.com continue; 1598135323f70b38e465761ab3e9817183750e3864dedisonn@google.com } 1608135323f70b38e465761ab3e9817183750e3864dedisonn@google.com gradients++; 1618135323f70b38e465761ab3e9817183750e3864dedisonn@google.com 162da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("{dup "); 163da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(info.fColorOffsets[i]); 164da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" le {"); 165da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (info.fColorOffsets[i - 1] != 0) { 166da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(info.fColorOffsets[i - 1]); 167da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" sub\n"); 168da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 169da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 170da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1], 17153648ab14e2f6a3cf07bd36b0964db8a0664b46adjsollen@google.com colorData[i], colorData[i - 1], result); 172da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("}\n"); 173da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 174da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 175da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Clamp the final color. 176da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("{pop "); 177da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[info.fColorCount - 1][0]); 178da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 179da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[info.fColorCount - 1][1]); 180da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 181da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[info.fColorCount - 1][2]); 182da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1838135323f70b38e465761ab3e9817183750e3864dedisonn@google.com for (int i = 0 ; i < gradients + 1; i++) { 184da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("} ifelse\n"); 185da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 186da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 187da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 188da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */ 189da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void tileModeCode(SkShader::TileMode mode, SkString* result) { 190da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (mode == SkShader::kRepeat_TileMode) { 191da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup truncate sub\n"); // Get the fractional part. 192da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1) 193da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return; 194da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 195da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 196da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (mode == SkShader::kMirror_TileMode) { 197da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Map t mod 2 into [0, 1, 1, 0]. 198da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Code Stack 199da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("abs " // Map negative to positive. 200da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "dup " // t.s t.s 201da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "truncate " // t.s t 202da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "dup " // t.s t t 203da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "cvi " // t.s t T 204da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "2 mod " // t.s t (i mod 2) 205da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "1 eq " // t.s t true|false 206da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "3 1 roll " // true|false t.s t 207da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "sub " // true|false 0.s 208da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "exch " // 0.s true|false 209da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "{1 exch sub} if\n"); // 1 - 0.s|0.s 210da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 211da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 212da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 21383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com/** 21483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * Returns PS function code that applies inverse perspective 21583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * to a x, y point. 21683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * The function assumes that the stack has at least two elements, 21783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * and that the top 2 elements are numeric values. 21883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * After executing this code on a PS stack, the last 2 elements are updated 21983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * while the rest of the stack is preserved intact. 22083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com * inversePerspectiveMatrix is the inverse perspective matrix. 22183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com */ 22283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString apply_perspective_to_coordinates( 22383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& inversePerspectiveMatrix) { 22483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com SkString code; 22583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com if (!inversePerspectiveMatrix.hasPerspective()) { 22683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com return code; 22783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com } 22883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 22983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // Perspective matrix should be: 23083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // 1 0 0 23183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // 0 1 0 23283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // p0 p1 p2 23383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 23483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p0 = inversePerspectiveMatrix[SkMatrix::kMPersp0]; 23583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p1 = inversePerspectiveMatrix[SkMatrix::kMPersp1]; 23683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p2 = inversePerspectiveMatrix[SkMatrix::kMPersp2]; 23783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 23883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // y = y / (p2 + p0 x + p1 y) 23983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // x = x / (p2 + p0 x + p1 y) 24083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 24183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // Input on stack: x y 24283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.append(" dup "); // x y y 24383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.appendScalar(p1); // x y y p1 24483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.append(" mul " // x y y*p1 24583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com " 2 index "); // x y y*p1 x 24683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.appendScalar(p0); // x y y p1 x p0 24783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.append(" mul "); // x y y*p1 x*p0 24883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.appendScalar(p2); // x y y p1 x*p0 p2 24983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com code.append(" add " // x y y*p1 x*p0+p2 25083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "add " // x y y*p1+x*p0+p2 25183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "3 1 roll " // y*p1+x*p0+p2 x y 25283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "2 index " // z x y y*p1+x*p0+p2 25383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "div " // y*p1+x*p0+p2 x y/(y*p1+x*p0+p2) 25483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "3 1 roll " // y/(y*p1+x*p0+p2) y*p1+x*p0+p2 x 25583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "exch " // y/(y*p1+x*p0+p2) x y*p1+x*p0+p2 25683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "div " // y/(y*p1+x*p0+p2) x/(y*p1+x*p0+p2) 25783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com "exch\n"); // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2) 25883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com return code; 25983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com} 26083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 26183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString linearCode(const SkShader::GradientInfo& info, 26283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) { 26383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com SkString function("{"); 26483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 26583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com function.append(apply_perspective_to_coordinates(perspectiveRemover)); 26683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 26783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com function.append("pop\n"); // Just ditch the y value. 268da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 269da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 270da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 271da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 272da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 273da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 27483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString radialCode(const SkShader::GradientInfo& info, 27583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) { 276da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString function("{"); 27783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 27883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com function.append(apply_perspective_to_coordinates(perspectiveRemover)); 27983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 280da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Find the distance from the origin. 281da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("dup " // x y y 282da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "mul " // x y^2 283da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "exch " // y^2 x 284da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "dup " // y^2 x x 285da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "mul " // y^2 x^2 286da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "add " // y^2+x^2 287da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "sqrt\n"); // sqrt(y^2+x^2) 288da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 289da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 290da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 291da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 292da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 293da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 294da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 295da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* The math here is all based on the description in Two_Point_Radial_Gradient, 296da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org with one simplification, the coordinate space has been scaled so that 297da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org Dr = 1. This means we don't need to scale the entire equation by 1/Dr^2. 298da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 29983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString twoPointRadialCode(const SkShader::GradientInfo& info, 30083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) { 301da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar dx = info.fPoint[0].fX - info.fPoint[1].fX; 302da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar dy = info.fPoint[0].fY - info.fPoint[1].fY; 303da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar sr = info.fRadius[0]; 304da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - SK_Scalar1; 305da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bool posRoot = info.fRadius[1] > info.fRadius[0]; 306da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 307da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // We start with a stack of (x y), copy it and then consume one copy in 308da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // order to calculate b and the other to calculate c. 309da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString function("{"); 31083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 31183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com function.append(apply_perspective_to_coordinates(perspectiveRemover)); 31283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 313da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("2 copy "); 314da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 315da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Calculate -b and b^2. 316da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(dy); 317da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" mul exch "); 318da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(dx); 319da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" mul add "); 320da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(sr); 321da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" sub 2 mul neg dup dup mul\n"); 322da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 323da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Calculate c 324da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("4 2 roll dup mul exch dup mul add "); 325da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(SkScalarMul(sr, sr)); 326da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" sub\n"); 327da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 328da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Calculate the determinate 329da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(SkScalarMul(SkIntToScalar(4), a)); 330da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" mul sub abs sqrt\n"); 331da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 332da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // And then the final value of t. 333da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (posRoot) { 334da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("sub "); 335da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 336da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("add "); 337da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 338da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(SkScalarMul(SkIntToScalar(2), a)); 339da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" div\n"); 340da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 341da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 342da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 343da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 344da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 345da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 346da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 3476219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com/* Conical gradient shader, based on the Canvas spec for radial gradients 348d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient 3496219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com */ 35083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString twoPointConicalCode(const SkShader::GradientInfo& info, 35183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) { 3526219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX; 3536219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY; 3546219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar r0 = info.fRadius[0]; 3556219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar dr = info.fRadius[1] - info.fRadius[0]; 356d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - 3576219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalarMul(dr, dr); 3586219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3596219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // First compute t, if the pixel falls outside the cone, then we'll end 3606219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // with 'false' on the stack, otherwise we'll push 'true' with t below it 3616219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3626219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // We start with a stack of (x y), copy it and then consume one copy in 3636219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // order to calculate b and the other to calculate c. 3646219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkString function("{"); 36583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 36683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com function.append(apply_perspective_to_coordinates(perspectiveRemover)); 36783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 3686219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("2 copy "); 3696219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3706219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr). 3716219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dy); 3726219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul exch "); 3736219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dx); 3746219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul add "); 3756219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(SkScalarMul(r0, dr)); 3766219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add -2 mul dup dup mul\n"); 3776219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3786219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // c = x^2 + y^2 + radius0^2 3796219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("4 2 roll dup mul exch dup mul add "); 3806219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(SkScalarMul(r0, r0)); 3816219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" sub dup 4 1 roll\n"); 3826219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3836219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // Contents of the stack at this point: c, b, b^2, c 3846219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3856219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if a = 0, then we collapse to a simpler linear case 3866219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com if (a == 0) { 3876219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3886219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // t = -c/b 3896219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("pop pop div neg dup "); 3906219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3916219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // compute radius(t) 3926219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dr); 3936219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul "); 3946219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(r0); 3956219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add\n"); 3966219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3976219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if r(t) < 0, then it's outside the cone 398ab2fe82840f37e92e7c45a36cac725c6fd2512c7rileya@google.com function.append("0 lt {pop false} {true} ifelse\n"); 3996219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4006219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com } else { 4016219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4026219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // quadratic case: the Canvas spec wants the largest 4036219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // root t for which radius(t) > 0 404d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 4056219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // compute the discriminant (b^2 - 4ac) 4066219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(SkScalarMul(SkIntToScalar(4), a)); 4076219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul sub dup\n"); 4086219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4096219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if d >= 0, proceed 4106219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("0 ge {\n"); 4116219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4126219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // an intermediate value we'll use to compute the roots: 4136219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // q = -0.5 * (b +/- sqrt(d)) 4146219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("sqrt exch dup 0 lt {exch -1 mul} if"); 4156219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add -0.5 mul dup\n"); 4166219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4176219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // first root = q / a 4186219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(a); 4196219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" div\n"); 4206219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4216219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // second root = c / q 4226219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("3 1 roll div\n"); 4236219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4246219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // put the larger root on top of the stack 4256219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("2 copy gt {exch} if\n"); 4266219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4276219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // compute radius(t) for larger root 4286219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("dup "); 4296219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dr); 4306219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul "); 4316219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(r0); 4326219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add\n"); 4336219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4346219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if r(t) > 0, we have our t, pop off the smaller root and we're done 4356219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" 0 gt {exch pop true}\n"); 4366219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4376219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // otherwise, throw out the larger one and try the smaller root 4386219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("{pop dup\n"); 4396219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dr); 4406219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul "); 4416219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(r0); 4426219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add\n"); 4436219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4446219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if r(t) < 0, push false, otherwise the smaller root is our t 445ab2fe82840f37e92e7c45a36cac725c6fd2512c7rileya@google.com function.append("0 le {pop false} {true} ifelse\n"); 4466219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("} ifelse\n"); 4476219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4486219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // d < 0, clear the stack and push false 449ab2fe82840f37e92e7c45a36cac725c6fd2512c7rileya@google.com function.append("} {pop pop pop false} ifelse\n"); 4506219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com } 4516219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4526219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if the pixel is in the cone, proceed to compute a color 4536219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("{"); 4546219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com tileModeCode(info.fTileMode, &function); 4556219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com gradientFunctionCode(info, &function); 4566219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4576219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // otherwise, just write black 4586219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("} {0 0 0} ifelse }"); 4596219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 4606219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com return function; 4616219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com} 4626219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 46383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic SkString sweepCode(const SkShader::GradientInfo& info, 46483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) { 465da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString function("{exch atan 360 div\n"); 466da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 467da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 468da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 469da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 470da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 471da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 472421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgclass SkPDFShader::State { 473421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgpublic: 474421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkShader::GradientType fType; 475421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkShader::GradientInfo fInfo; 47693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoFree fColorData; // This provides storage for arrays in fInfo. 477421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkMatrix fCanvasTransform; 478421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkMatrix fShaderTransform; 479421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkIRect fBBox; 480421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 481421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkBitmap fImage; 482421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org uint32_t fPixelGeneration; 483421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkShader::TileMode fImageTileModes[2]; 484421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 48593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org State(const SkShader& shader, const SkMatrix& canvasTransform, 48693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const SkIRect& bbox); 48793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 488421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org bool operator==(const State& b) const; 48993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 49093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFShader::State* CreateAlphaToLuminosityState() const; 49193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFShader::State* CreateOpaqueState() const; 49293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 49393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org bool GradientHasAlpha() const; 49493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 49593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgprivate: 49693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org State(const State& other); 49793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org State operator=(const State& rhs); 49893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org void AllocateGradientInfoStorage(); 499421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}; 500421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 501421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgclass SkPDFFunctionShader : public SkPDFDict, public SkPDFShader { 502ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org SK_DECLARE_INST_COUNT(SkPDFFunctionShader) 503421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgpublic: 504a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org explicit SkPDFFunctionShader(SkPDFShader::State* state); 50505141c23ed2731bf04e7a1ca2a03ca23014b7222robertphillips@google.com virtual ~SkPDFFunctionShader() { 506421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org if (isValid()) { 507421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org RemoveShader(this); 508421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org } 509421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org fResources.unrefAll(); 510b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org } 511da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 512386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org virtual bool isValid() { return fResources.count() > 0; } 513da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 5146addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 5156addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com SkTSet<SkPDFObject*>* newResourceObjects) { 5166addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com GetResourcesHelper(&fResources, 5176addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com knownResourceObjects, 5186addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com newResourceObjects); 519421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org } 520da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 521421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgprivate: 522421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org static SkPDFObject* RangeObject(); 523da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 524421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkTDArray<SkPDFObject*> fResources; 525421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkAutoTDelete<const SkPDFShader::State> fState; 526da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 527421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain); 528ab1c13864df34aecfd4840ea7d1e4f8730b44f4ecommit-bot@chromium.org typedef SkPDFDict INHERITED; 529421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}; 530421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 53193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 53293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * A shader for PDF gradients. This encapsulates the function shader 53393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * inside a tiling pattern while providing a common pattern interface. 53493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * The encapsulation allows the use of a SMask for transparency gradients. 53593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 53693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgclass SkPDFAlphaFunctionShader : public SkPDFStream, public SkPDFShader { 53793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgpublic: 53893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state); 53993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org virtual ~SkPDFAlphaFunctionShader() { 54093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (isValid()) { 54193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org RemoveShader(this); 54293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 54393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 54493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 54593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org virtual bool isValid() { 54693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return fColorShader.get() != NULL; 54793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 54893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 54993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgprivate: 55093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTDelete<const SkPDFShader::State> fState; 55193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 55293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFGraphicState* CreateSMaskGraphicState(); 55393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 55493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 55593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkTSet<SkPDFObject*>* newResourceObjects) { 55693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fResourceDict->getReferencedResources(knownResourceObjects, 55793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org newResourceObjects, 55893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org true); 55993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 56093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 56193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTUnref<SkPDFObject> fColorShader; 56293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTUnref<SkPDFResourceDict> fResourceDict; 56393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org}; 56493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 565421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgclass SkPDFImageShader : public SkPDFStream, public SkPDFShader { 566421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgpublic: 567a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org explicit SkPDFImageShader(SkPDFShader::State* state); 56805141c23ed2731bf04e7a1ca2a03ca23014b7222robertphillips@google.com virtual ~SkPDFImageShader() { 5698e473760d7b495b06c600c5dc5e5fd42876e159fedisonn@google.com if (isValid()) { 5708e473760d7b495b06c600c5dc5e5fd42876e159fedisonn@google.com RemoveShader(this); 5718e473760d7b495b06c600c5dc5e5fd42876e159fedisonn@google.com } 572421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org fResources.unrefAll(); 573421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org } 574421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 575386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org virtual bool isValid() { return size() > 0; } 576386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org 5776addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 5786addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com SkTSet<SkPDFObject*>* newResourceObjects) { 5796addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com GetResourcesHelper(&fResources.toArray(), 5806addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com knownResourceObjects, 5816addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com newResourceObjects); 582da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 583421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 584421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgprivate: 5856addb1930013ebb2f984045141650fd7afcfa90fedisonn@google.com SkTSet<SkPDFObject*> fResources; 586421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkAutoTDelete<const SkPDFShader::State> fState; 587421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}; 588421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 589421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFShader::SkPDFShader() {} 590421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 591421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org// static 59293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgSkPDFObject* SkPDFShader::GetPDFShaderByState(State* inState) { 593421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkPDFObject* result; 59493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 59593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTDelete<State> shaderState(inState); 596da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org if (shaderState.get()->fType == SkShader::kNone_GradientType && 597da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org shaderState.get()->fImage.isNull()) { 598da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // TODO(vandebo) This drops SKComposeShader on the floor. We could 599da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // handle compose shader by pulling things up to a layer, drawing with 600da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // the first shader, applying the xfer mode and drawing again with the 601da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // second shader, then applying the layer to the original drawing. 602da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org return NULL; 603da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org } 604da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 605da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org ShaderCanonicalEntry entry(NULL, shaderState.get()); 606b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org int index = CanonicalShaders().find(entry); 607da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (index >= 0) { 608421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org result = CanonicalShaders()[index].fPDFShader; 609da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->ref(); 610da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return result; 611da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 612386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org 613386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org bool valid = false; 614da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // The PDFShader takes ownership of the shaderSate. 615421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org if (shaderState.get()->fType == SkShader::kNone_GradientType) { 616386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org SkPDFImageShader* imageShader = 617386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org new SkPDFImageShader(shaderState.detach()); 618386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org valid = imageShader->isValid(); 619386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org result = imageShader; 620421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org } else { 62193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (shaderState.get()->GradientHasAlpha()) { 62293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFAlphaFunctionShader* gradientShader = 62393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkNEW_ARGS(SkPDFAlphaFunctionShader, (shaderState.detach())); 62493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org valid = gradientShader->isValid(); 62593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org result = gradientShader; 62693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } else { 62793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFFunctionShader* functionShader = 62893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkNEW_ARGS(SkPDFFunctionShader, (shaderState.detach())); 62993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org valid = functionShader->isValid(); 63093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org result = functionShader; 63193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 632da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 633386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org if (!valid) { 634386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org delete result; 635386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return NULL; 636386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org } 637421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org entry.fPDFShader = result; 638b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org CanonicalShaders().push(entry); 639421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org return result; // return the reference that came from new. 640da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 641da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 642da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org// static 64393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgvoid SkPDFShader::RemoveShader(SkPDFObject* shader) { 64493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoMutexAcquire lock(CanonicalShadersMutex()); 64593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org ShaderCanonicalEntry entry(shader, NULL); 64693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org int index = CanonicalShaders().find(entry); 64793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkASSERT(index >= 0); 64893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org CanonicalShaders().removeShuffle(index); 64993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 65093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 65193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org// static 65293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgSkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, 65393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const SkMatrix& matrix, 65493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const SkIRect& surfaceBBox) { 65593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoMutexAcquire lock(CanonicalShadersMutex()); 65693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return GetPDFShaderByState( 65793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkNEW_ARGS(State, (shader, matrix, surfaceBBox))); 65893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 65993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 66093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org// static 661b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.orgSkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() { 66224480bc71ef6c754030cb3f98672da1c8fb3a63bhalcanary SkPDFShader::CanonicalShadersMutex().assertHeld(); 663da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders; 664da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return gCanonicalShaders; 665da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 666da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 667da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org// static 6681771cbf43d9a1334e3d870c635b4215bb888dd98digit@google.comSkBaseMutex& SkPDFShader::CanonicalShadersMutex() { 6691771cbf43d9a1334e3d870c635b4215bb888dd98digit@google.com SK_DECLARE_STATIC_MUTEX(gCanonicalShadersMutex); 670da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return gCanonicalShadersMutex; 671da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 672da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 673da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org// static 674421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFObject* SkPDFFunctionShader::RangeObject() { 67524480bc71ef6c754030cb3f98672da1c8fb3a63bhalcanary SkPDFShader::CanonicalShadersMutex().assertHeld(); 676da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org static SkPDFArray* range = NULL; 677b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org // This method is only used with CanonicalShadersMutex, so it's safe to 678da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // populate domain. 679da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (range == NULL) { 680da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org range = new SkPDFArray; 681da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org range->reserve(6); 682c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(0); 683c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(1); 684c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(0); 685c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(1); 686c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(0); 687c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(1); 688da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 689da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return range; 690da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 691da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 69293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgstatic SkPDFResourceDict* get_gradient_resource_dict( 69393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFObject* functionShader, 69493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFObject* gState) { 69593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFResourceDict* dict = new SkPDFResourceDict(); 69693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 69793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (functionShader != NULL) { 69893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org dict->insertResourceAsReference( 69993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFResourceDict::kPattern_ResourceType, 0, functionShader); 70093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 70193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (gState != NULL) { 70293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org dict->insertResourceAsReference( 70393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFResourceDict::kExtGState_ResourceType, 0, gState); 70493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 70593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 70693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return dict; 70793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 70893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 70993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgstatic void populate_tiling_pattern_dict(SkPDFDict* pattern, 71093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkRect& bbox, SkPDFDict* resources, 71193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const SkMatrix& matrix) { 71293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const int kTiling_PatternType = 1; 71393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const int kColoredTilingPattern_PaintType = 1; 71493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org const int kConstantSpacing_TilingType = 1; 71593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 71693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertName("Type", "Pattern"); 71793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertInt("PatternType", kTiling_PatternType); 71893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertInt("PaintType", kColoredTilingPattern_PaintType); 71993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertInt("TilingType", kConstantSpacing_TilingType); 72093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insert("BBox", SkPDFUtils::RectToArray(bbox))->unref(); 72193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertScalar("XStep", bbox.width()); 72293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insertScalar("YStep", bbox.height()); 72393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insert("Resources", resources); 72493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (!matrix.isIdentity()) { 72593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern->insert("Matrix", SkPDFUtils::MatrixToArray(matrix))->unref(); 72693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 72793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 72893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 72993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 73093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Creates a content stream which fills the pattern P0 across bounds. 73193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * @param gsIndex A graphics state resource index to apply, or <0 if no 73293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * graphics state to apply. 73393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 73493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgstatic SkStream* create_pattern_fill_content(int gsIndex, SkRect& bounds) { 73593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkDynamicMemoryWStream content; 73693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (gsIndex >= 0) { 73793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFUtils::ApplyGraphicState(gsIndex, &content); 73893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 73993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFUtils::ApplyPattern(0, &content); 74093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFUtils::AppendRectangle(bounds, &content); 74193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPath::kEvenOdd_FillType, 74293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org &content); 74393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 74493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return content.detachAsStream(); 74593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 74693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 74793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 74893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Creates a ExtGState with the SMask set to the luminosityShader in 74993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * luminosity mode. The shader pattern extends to the bbox. 75093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 75193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgSkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() { 75293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkRect bbox; 75393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org bbox.set(fState.get()->fBBox); 75493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 75593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTUnref<SkPDFObject> luminosityShader( 75693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFShader::GetPDFShaderByState( 75793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fState->CreateAlphaToLuminosityState())); 75893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 75993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTUnref<SkStream> alphaStream(create_pattern_fill_content(-1, bbox)); 76093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 76193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTUnref<SkPDFResourceDict> 76293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org resources(get_gradient_resource_dict(luminosityShader, NULL)); 76393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 76493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTUnref<SkPDFFormXObject> alphaMask( 76593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org new SkPDFFormXObject(alphaStream.get(), bbox, resources.get())); 76693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 76793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return SkPDFGraphicState::GetSMaskGraphicState( 76893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org alphaMask.get(), false, 76993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFGraphicState::kLuminosity_SMaskMode); 77093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 77193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 77293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgSkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state) 77393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org : fState(state) { 77493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkRect bbox; 77593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org bbox.set(fState.get()->fBBox); 77693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 77793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fColorShader.reset( 77893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFShader::GetPDFShaderByState(state->CreateOpaqueState())); 77993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 78093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org // Create resource dict with alpha graphics state as G0 and 78193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org // pattern shader as P0, then write content stream. 78293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTUnref<SkPDFGraphicState> alphaGs(CreateSMaskGraphicState()); 78393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fResourceDict.reset( 78493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org get_gradient_resource_dict(fColorShader.get(), alphaGs.get())); 78593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 78693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAutoTUnref<SkStream> colorStream( 78793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org create_pattern_fill_content(0, bbox)); 78893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org setData(colorStream.get()); 78993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 79093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org populate_tiling_pattern_dict(this, bbox, fResourceDict.get(), 79193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkMatrix::I()); 79293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 79393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 79483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com// Finds affine and persp such that in = affine * persp. 79583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com// but it returns the inverse of perspective matrix. 79683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.comstatic bool split_perspective(const SkMatrix in, SkMatrix* affine, 79783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com SkMatrix* perspectiveInverse) { 79883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p2 = in[SkMatrix::kMPersp2]; 79983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 80083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com if (SkScalarNearlyZero(p2)) { 80183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com return false; 80283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com } 80383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 80483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar zero = SkIntToScalar(0); 80583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar one = SkIntToScalar(1); 80683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 80783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar sx = in[SkMatrix::kMScaleX]; 80883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar kx = in[SkMatrix::kMSkewX]; 80983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar tx = in[SkMatrix::kMTransX]; 81083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar ky = in[SkMatrix::kMSkewY]; 81183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar sy = in[SkMatrix::kMScaleY]; 81283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar ty = in[SkMatrix::kMTransY]; 81383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p0 = in[SkMatrix::kMPersp0]; 81483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkScalar p1 = in[SkMatrix::kMPersp1]; 81583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 81683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // Perspective matrix would be: 81783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // 1 0 0 81883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // 0 1 0 81983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // p0 p1 p2 82083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // But we need the inverse of persp. 82183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com perspectiveInverse->setAll(one, zero, zero, 82283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com zero, one, zero, 82383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com -p0/p2, -p1/p2, 1/p2); 82483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 82583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com affine->setAll(sx - p0 * tx / p2, kx - p1 * tx / p2, tx / p2, 82683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com ky - p0 * ty / p2, sy - p1 * ty / p2, ty / p2, 82783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com zero, zero, one); 82883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 82983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com return true; 83083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com} 83183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 832421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) 833421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org : SkPDFDict("Pattern"), 834421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org fState(state) { 83583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com SkString (*codeFunction)(const SkShader::GradientInfo& info, 83683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com const SkMatrix& perspectiveRemover) = NULL; 837da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkPoint transformPoints[2]; 838da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 839da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Depending on the type of the gradient, we want to transform the 840da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // coordinate space in different ways. 841da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org const SkShader::GradientInfo* info = &fState.get()->fInfo; 842da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[0] = info->fPoint[0]; 843da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = info->fPoint[1]; 844da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org switch (fState.get()->fType) { 845da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kLinear_GradientType: 846da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &linearCode; 847da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 848da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kRadial_GradientType: 849da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = transformPoints[0]; 850da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1].fX += info->fRadius[0]; 851da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &radialCode; 852da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 853da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kRadial2_GradientType: { 854421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org // Bail out if the radii are the same. Empty fResources signals 855421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org // an error and isValid will return false. 856da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (info->fRadius[0] == info->fRadius[1]) { 857da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return; 858da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 859da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = transformPoints[0]; 860da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar dr = info->fRadius[1] - info->fRadius[0]; 861da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1].fX += dr; 862da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &twoPointRadialCode; 863da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 864da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 8656219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com case SkShader::kConical_GradientType: { 8666219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com transformPoints[1] = transformPoints[0]; 8676219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com transformPoints[1].fX += SK_Scalar1; 8686219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com codeFunction = &twoPointConicalCode; 8696219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com break; 8706219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com } 871da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kSweep_GradientType: 872da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = transformPoints[0]; 873c39c8674c94dba8b1ffe938cd99c825320cc1475vandebo@chromium.org transformPoints[1].fX += SK_Scalar1; 874da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &sweepCode; 875da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 876da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kColor_GradientType: 877da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kNone_GradientType: 878020798af6780ba29156f4daec87c29ae9e4f4a12vandebo@chromium.org default: 879da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return; 880da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 881da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 882da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Move any scaling (assuming a unit gradient) or translation 883da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // (and rotation for linear gradient), of the final gradient from 884da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // info->fPoints to the matrix (updating bbox appropriately). Now 885da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // the gradient can be drawn on on the unit segment. 886da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix mapperMatrix; 887da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org unitToPointsMatrix(transformPoints, &mapperMatrix); 88883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 889da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix finalMatrix = fState.get()->fCanvasTransform; 890da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org finalMatrix.preConcat(fState.get()->fShaderTransform); 891ace2269edfed9dfd3097597f1698921aaddf80a1commit-bot@chromium.org finalMatrix.preConcat(mapperMatrix); 892ace2269edfed9dfd3097597f1698921aaddf80a1commit-bot@chromium.org 89383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // Preserves as much as posible in the final matrix, and only removes 89483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // the perspective. The inverse of the perspective is stored in 89583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // perspectiveInverseOnly matrix and has 3 useful numbers 89683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // (p0, p1, p2), while everything else is either 0 or 1. 89783d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com // In this way the shader will handle it eficiently, with minimal code. 89883d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com SkMatrix perspectiveInverseOnly = SkMatrix::I(); 89983d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com if (finalMatrix.hasPerspective()) { 90083d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com if (!split_perspective(finalMatrix, 90183d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com &finalMatrix, &perspectiveInverseOnly)) { 90283d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com return; 90383d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com } 90483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com } 90583d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com 906da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRect bbox; 907da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bbox.set(fState.get()->fBBox); 908e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (!inverseTransformBBox(finalMatrix, &bbox)) { 909386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return; 910386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org } 911da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 912d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkAutoTUnref<SkPDFArray> domain(new SkPDFArray); 913da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org domain->reserve(4); 914c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fLeft); 915c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fRight); 916c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fTop); 917c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fBottom); 918da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 919da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString functionCode; 920da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // The two point radial gradient further references fState.get()->fInfo 921da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // in translating from x, y coordinates to the t parameter. So, we have 922da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // to transform the points and radii according to the calculated matrix. 923da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fState.get()->fType == SkShader::kRadial2_GradientType) { 924da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkShader::GradientInfo twoPointRadialInfo = *info; 925da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix inverseMapperMatrix; 926b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org if (!mapperMatrix.invert(&inverseMapperMatrix)) { 927386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return; 928b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org } 929da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); 930da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org twoPointRadialInfo.fRadius[0] = 931da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverseMapperMatrix.mapRadius(info->fRadius[0]); 932da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org twoPointRadialInfo.fRadius[1] = 933da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverseMapperMatrix.mapRadius(info->fRadius[1]); 93483d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly); 935da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 93683d8eda890def8c119794deeec6244c67da83ac8edisonn@google.com functionCode = codeFunction(*info, perspectiveInverseOnly); 937da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 938da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 939d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict); 940c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com pdfShader->insertInt("ShadingType", 1); 941c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com pdfShader->insertName("ColorSpace", "DeviceRGB"); 942da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org pdfShader->insert("Domain", domain.get()); 943d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org 944d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkPDFStream* function = makePSFunction(functionCode, domain.get()); 945d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org pdfShader->insert("Function", new SkPDFObjRef(function))->unref(); 946d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org fResources.push(function); // Pass ownership to resource list. 947da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 948421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insertInt("PatternType", 2); 949421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref(); 950421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insert("Shading", pdfShader.get()); 951da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 952da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 953421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) { 954da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fState.get()->fImage.lockPixels(); 955da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 956e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // The image shader pattern cell will be drawn into a separate device 957e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // in pattern cell space (no scaling on the bitmap, though there may be 958e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // translations so that all content is in the device, coordinates > 0). 959e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 960e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // Map clip bounds to shader space to ensure the device is large enough 961e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // to handle fake clamping. 962da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix finalMatrix = fState.get()->fCanvasTransform; 963da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org finalMatrix.preConcat(fState.get()->fShaderTransform); 964e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkRect deviceBounds; 965e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org deviceBounds.set(fState.get()->fBBox); 966e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (!inverseTransformBBox(finalMatrix, &deviceBounds)) { 967386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return; 968386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org } 969da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 970e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org const SkBitmap* image = &fState.get()->fImage; 971e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkRect bitmapBounds; 972e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org image->getBounds(&bitmapBounds); 973e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 974e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // For tiling modes, the bounds should be extended to include the bitmap, 975e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // otherwise the bitmap gets clipped out and the shader is empty and awful. 976e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // For clamp modes, we're only interested in the clip region, whether 977e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // or not the main bitmap is in it. 978e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkShader::TileMode tileModes[2]; 979e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org tileModes[0] = fState.get()->fImageTileModes[0]; 980e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org tileModes[1] = fState.get()->fImageTileModes[1]; 981e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (tileModes[0] != SkShader::kClamp_TileMode || 982e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org tileModes[1] != SkShader::kClamp_TileMode) { 983e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org deviceBounds.join(bitmapBounds); 984e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org } 985e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 98675f97e452e8f2ee55cd2b283df7d7734f48bc2bfvandebo@chromium.org SkMatrix unflip; 987e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org unflip.setTranslate(0, SkScalarRoundToScalar(deviceBounds.height())); 988663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org unflip.preScale(SK_Scalar1, -SK_Scalar1); 989e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()), 990e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com SkScalarRoundToInt(deviceBounds.height())); 9915e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org // TODO(edisonn): should we pass here the DCT encoder of the destination device? 9925e00989a283111cef05bed8102e45c16651e43e4commit-bot@chromium.org // TODO(edisonn): NYI Perspective, use SkPDFDeviceFlattener. 993152612938020fa46999f33668027d5bc0f7afd18ctguil@chromium.org SkPDFDevice pattern(size, size, unflip); 994da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkCanvas canvas(&pattern); 995da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 996e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkRect patternBBox; 997e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org image->getBounds(&patternBBox); 998da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 999e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // Translate the canvas so that the bitmap origin is at (0, 0). 1000e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org canvas.translate(-deviceBounds.left(), -deviceBounds.top()); 1001e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org patternBBox.offset(-deviceBounds.left(), -deviceBounds.top()); 1002e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // Undo the translation in the final matrix 1003e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org finalMatrix.preTranslate(deviceBounds.left(), deviceBounds.top()); 1004e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 1005e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // If the bitmap is out of bounds (i.e. clamp mode where we only see the 1006e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // stretched sides), canvas will clip this out and the extraneous data 1007e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org // won't be saved to the PDF. 1008da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmap(*image, 0, 0); 1009e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 1010e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkScalar width = SkIntToScalar(image->width()); 1011e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org SkScalar height = SkIntToScalar(image->height()); 1012da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1013da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Tiling is implied. First we handle mirroring. 1014da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode) { 1015da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix xMirror; 1016da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org xMirror.setScale(-1, 1); 1017da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org xMirror.postTranslate(2 * width, 0); 1018da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(*image, xMirror); 1019da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org patternBBox.fRight += width; 1020da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1021da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kMirror_TileMode) { 1022da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix yMirror; 1023663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org yMirror.setScale(SK_Scalar1, -SK_Scalar1); 1024da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org yMirror.postTranslate(0, 2 * height); 1025da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(*image, yMirror); 1026da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org patternBBox.fBottom += height; 1027da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1028da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode && 1029da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModes[1] == SkShader::kMirror_TileMode) { 1030da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix mirror; 1031da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org mirror.setScale(-1, -1); 1032da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org mirror.postTranslate(2 * width, 2 * height); 1033da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(*image, mirror); 1034da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1035da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1036da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Then handle Clamping, which requires expanding the pattern canvas to 1037da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // cover the entire surfaceBBox. 1038da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1039da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // If both x and y are in clamp mode, we start by filling in the corners. 1040da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // (Which are just a rectangles of the corner colors.) 1041da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kClamp_TileMode && 1042da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModes[1] == SkShader::kClamp_TileMode) { 1043da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkPaint paint; 1044da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRect rect; 1045e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org rect = SkRect::MakeLTRB(deviceBounds.left(), deviceBounds.top(), 0, 0); 1046da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 1047da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org paint.setColor(image->getColor(0, 0)); 1048da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 1049da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1050da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1051e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org rect = SkRect::MakeLTRB(width, deviceBounds.top(), 1052e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org deviceBounds.right(), 0); 1053da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 105454ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org paint.setColor(image->getColor(image->width() - 1, 0)); 1055da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 1056da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1057da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1058e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org rect = SkRect::MakeLTRB(width, height, 1059e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org deviceBounds.right(), deviceBounds.bottom()); 1060da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 106154ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org paint.setColor(image->getColor(image->width() - 1, 106254ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org image->height() - 1)); 1063da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 1064da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1065da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1066e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org rect = SkRect::MakeLTRB(deviceBounds.left(), height, 1067e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org 0, deviceBounds.bottom()); 1068da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 106954ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org paint.setColor(image->getColor(0, image->height() - 1)); 1070da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 1071da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1072da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1073da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1074da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Then expand the left, right, top, then bottom. 1075da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kClamp_TileMode) { 107654ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height()); 1077e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (deviceBounds.left() < 0) { 1078da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap left; 1079da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&left, subset)); 1080da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1081da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix leftMatrix; 1082e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org leftMatrix.setScale(-deviceBounds.left(), 1); 1083e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org leftMatrix.postTranslate(deviceBounds.left(), 0); 1084da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(left, leftMatrix); 1085da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1086da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kMirror_TileMode) { 1087663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org leftMatrix.postScale(SK_Scalar1, -SK_Scalar1); 1088da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org leftMatrix.postTranslate(0, 2 * height); 1089da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(left, leftMatrix); 1090da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1091be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org patternBBox.fLeft = 0; 1092da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1093da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1094e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (deviceBounds.right() > width) { 1095da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap right; 109654ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org subset.offset(image->width() - 1, 0); 1097da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&right, subset)); 1098da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1099da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix rightMatrix; 1100e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org rightMatrix.setScale(deviceBounds.right() - width, 1); 1101da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rightMatrix.postTranslate(width, 0); 1102da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(right, rightMatrix); 1103da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1104da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kMirror_TileMode) { 1105663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org rightMatrix.postScale(SK_Scalar1, -SK_Scalar1); 1106da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rightMatrix.postTranslate(0, 2 * height); 1107da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(right, rightMatrix); 1108da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1109e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org patternBBox.fRight = deviceBounds.width(); 1110da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1111da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1112da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1113da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kClamp_TileMode) { 111454ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1); 1115e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (deviceBounds.top() < 0) { 1116da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap top; 1117da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&top, subset)); 1118da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1119da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix topMatrix; 1120e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org topMatrix.setScale(SK_Scalar1, -deviceBounds.top()); 1121e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org topMatrix.postTranslate(0, deviceBounds.top()); 1122da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(top, topMatrix); 1123da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1124da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode) { 1125da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org topMatrix.postScale(-1, 1); 1126da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org topMatrix.postTranslate(2 * width, 0); 1127da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(top, topMatrix); 1128da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1129be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org patternBBox.fTop = 0; 1130da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1131da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1132e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org if (deviceBounds.bottom() > height) { 1133da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap bottom; 113454ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org subset.offset(0, image->height() - 1); 1135da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&bottom, subset)); 1136da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1137da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix bottomMatrix; 1138e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height); 1139da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bottomMatrix.postTranslate(0, height); 1140da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(bottom, bottomMatrix); 1141da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1142da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode) { 1143da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bottomMatrix.postScale(-1, 1); 1144da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bottomMatrix.postTranslate(2 * width, 0); 1145da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(bottom, bottomMatrix); 1146da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1147e324cc69be2be62a76cef52ba3562771af02f315commit-bot@chromium.org patternBBox.fBottom = deviceBounds.height(); 1148da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1149da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1150da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1151da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Put the canvas into the pattern stream (fContent). 1152d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org SkAutoTUnref<SkStream> content(pattern.content()); 1153d96d17b9c113ac694138224249ff2ce643e961ddvandebo@chromium.org setData(content.get()); 115447401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org SkPDFResourceDict* resourceDict = pattern.getResourceDict(); 115547401354074549d8591da7fa115241766d3ee3d2commit-bot@chromium.org resourceDict->getReferencedResources(fResources, &fResources, false); 1156da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 115793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org populate_tiling_pattern_dict(this, patternBBox, 115893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org pattern.getResourceDict(), finalMatrix); 1159da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1160da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fState.get()->fImage.unlockPixels(); 1161da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 1162da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1163421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, 1164421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkPDFArray* domain) { 1165421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(), 1166421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org psCode.size())); 1167421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkPDFStream* result = new SkPDFStream(funcData.get()); 1168c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com result->insertInt("FunctionType", 4); 1169da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->insert("Domain", domain); 1170f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com result->insert("Range", RangeObject()); 1171da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return result; 1172da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 1173da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1174421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFShader::ShaderCanonicalEntry::ShaderCanonicalEntry(SkPDFObject* pdfShader, 1175421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org const State* state) 1176421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org : fPDFShader(pdfShader), 1177421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org fState(state) { 1178421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org} 1179421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 1180421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgbool SkPDFShader::ShaderCanonicalEntry::operator==( 1181421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org const ShaderCanonicalEntry& b) const { 1182421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org return fPDFShader == b.fPDFShader || 1183421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org (fState != NULL && b.fState != NULL && *fState == *b.fState); 1184421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org} 1185421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 1186da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgbool SkPDFShader::State::operator==(const SkPDFShader::State& b) const { 1187da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fType != b.fType || 1188da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fCanvasTransform != b.fCanvasTransform || 1189da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fShaderTransform != b.fShaderTransform || 1190da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fBBox != b.fBBox) { 1191da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1192da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1193da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1194da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fType == SkShader::kNone_GradientType) { 1195da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fPixelGeneration != b.fPixelGeneration || 1196da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fPixelGeneration == 0 || 1197da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fImageTileModes[0] != b.fImageTileModes[0] || 1198da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fImageTileModes[1] != b.fImageTileModes[1]) { 1199da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1200da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1201da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 1202da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fColorCount != b.fInfo.fColorCount || 1203da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org memcmp(fInfo.fColors, b.fInfo.fColors, 1204da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org sizeof(SkColor) * fInfo.fColorCount) != 0 || 1205da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org memcmp(fInfo.fColorOffsets, b.fInfo.fColorOffsets, 1206da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org sizeof(SkScalar) * fInfo.fColorCount) != 0 || 1207da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fPoint[0] != b.fInfo.fPoint[0] || 1208da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fTileMode != b.fInfo.fTileMode) { 1209da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1210da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1211da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1212da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org switch (fType) { 1213da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kLinear_GradientType: 1214da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fPoint[1] != b.fInfo.fPoint[1]) { 1215da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1216da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1217da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 1218da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kRadial_GradientType: 1219da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fRadius[0] != b.fInfo.fRadius[0]) { 1220da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1221da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1222da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 1223da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kRadial2_GradientType: 12244908533aef9830dc1c18552c305ed6ccb286f4f2reed@google.com case SkShader::kConical_GradientType: 1225da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fPoint[1] != b.fInfo.fPoint[1] || 1226da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fRadius[0] != b.fInfo.fRadius[0] || 1227da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fRadius[1] != b.fInfo.fRadius[1]) { 1228da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 1229da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1230da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 1231da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kSweep_GradientType: 1232da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kNone_GradientType: 1233da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kColor_GradientType: 1234da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 1235da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1236da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1237da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return true; 1238da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 1239da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1240da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgSkPDFShader::State::State(const SkShader& shader, 1241da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org const SkMatrix& canvasTransform, const SkIRect& bbox) 1242da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org : fCanvasTransform(canvasTransform), 1243e1bc274295ec57cb3d3f01aaa8abff3b49c76c73vandebo@chromium.org fBBox(bbox), 1244e1bc274295ec57cb3d3f01aaa8abff3b49c76c73vandebo@chromium.org fPixelGeneration(0) { 1245da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fColorCount = 0; 1246da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fColors = NULL; 1247da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fColorOffsets = NULL; 1248f94b3a4cebd4adab09c40ebe23c02a615e10c394bsalomon@google.com fShaderTransform = shader.getLocalMatrix(); 1249e1bc274295ec57cb3d3f01aaa8abff3b49c76c73vandebo@chromium.org fImageTileModes[0] = fImageTileModes[1] = SkShader::kClamp_TileMode; 1250da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1251da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fType = shader.asAGradient(&fInfo); 1252da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 1253da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fType == SkShader::kNone_GradientType) { 1254da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkShader::BitmapType bitmapType; 1255da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix matrix; 125691f319c5dc4493384f0a52aaeef3dcc311ef6ed0rileya@google.com bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes); 1257da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (bitmapType != SkShader::kDefault_BitmapType) { 1258da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fImage.reset(); 1259da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return; 1260da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1261da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkASSERT(matrix.isIdentity()); 1262da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fPixelGeneration = fImage.getGenerationID(); 1263da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 126493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org AllocateGradientInfoStorage(); 1265da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org shader.asAGradient(&fInfo); 1266da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 1267da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 126893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 126993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgSkPDFShader::State::State(const SkPDFShader::State& other) 127093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org : fType(other.fType), 127193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fCanvasTransform(other.fCanvasTransform), 127293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fShaderTransform(other.fShaderTransform), 127393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fBBox(other.fBBox) 127493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org{ 127593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org // Only gradients supported for now, since that is all that is used. 127693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org // If needed, image state copy constructor can be added here later. 127793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkASSERT(fType != SkShader::kNone_GradientType); 127893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 127993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (fType != SkShader::kNone_GradientType) { 128093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo = other.fInfo; 128193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 128293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org AllocateGradientInfoStorage(); 128393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org for (int i = 0; i < fInfo.fColorCount; i++) { 128493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo.fColors[i] = other.fInfo.fColors[i]; 128593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo.fColorOffsets[i] = other.fInfo.fColorOffsets[i]; 128693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 128793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 128893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 128993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 129093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 129193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Create a copy of this gradient state with alpha assigned to RGB luminousity. 129293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Only valid for gradient states. 129393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 129493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgSkPDFShader::State* SkPDFShader::State::CreateAlphaToLuminosityState() const { 129593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkASSERT(fType != SkShader::kNone_GradientType); 129693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 129793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFShader::State* newState = new SkPDFShader::State(*this); 129893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 129993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org for (int i = 0; i < fInfo.fColorCount; i++) { 130093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAlpha alpha = SkColorGetA(fInfo.fColors[i]); 130193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org newState->fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha); 130293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 130393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 130493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return newState; 130593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 130693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 130793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 130893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Create a copy of this gradient state with alpha set to fully opaque 130993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Only valid for gradient states. 131093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 131193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgSkPDFShader::State* SkPDFShader::State::CreateOpaqueState() const { 131293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkASSERT(fType != SkShader::kNone_GradientType); 131393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 131493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkPDFShader::State* newState = new SkPDFShader::State(*this); 131593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org for (int i = 0; i < fInfo.fColorCount; i++) { 131693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org newState->fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i], 131793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SK_AlphaOPAQUE); 131893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 131993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 132093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return newState; 132193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 132293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 132393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org/** 132493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org * Returns true if state is a gradient and the gradient has alpha. 132593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org */ 132693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgbool SkPDFShader::State::GradientHasAlpha() const { 132793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (fType == SkShader::kNone_GradientType) { 132893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return false; 132993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 133093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 133193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org for (int i = 0; i < fInfo.fColorCount; i++) { 133293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org SkAlpha alpha = SkColorGetA(fInfo.fColors[i]); 133393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org if (alpha != SK_AlphaOPAQUE) { 133493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return true; 133593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 133693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org } 133793a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org return false; 133893a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 133993a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org 134093a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.orgvoid SkPDFShader::State::AllocateGradientInfoStorage() { 134193a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fColorData.set(sk_malloc_throw( 134293a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); 134393a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); 134493a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org fInfo.fColorOffsets = 134593a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); 134693a2e213441c75033b04365c7d68c8d3887288accommit-bot@chromium.org} 1347