SkPDFShader.cpp revision 91f319c5dc4493384f0a52aaeef3dcc311ef6ed0
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 12da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkCanvas.h" 13421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org#include "SkData.h" 14da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkPDFCatalog.h" 15da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkPDFDevice.h" 16da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkPDFTypes.h" 17da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkPDFUtils.h" 18da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkScalar.h" 19da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkStream.h" 20316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com#include "SkTemplates.h" 21da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkThread.h" 22da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org#include "SkTypes.h" 23da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 24386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.orgstatic bool transformBBox(const SkMatrix& matrix, SkRect* bbox) { 25da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix inverse; 26b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org if (!matrix.invert(&inverse)) { 27386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return false; 28b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org } 29da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverse.mapRect(bbox); 30386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return true; 31da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 32da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 33da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) { 34da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkVector vec = pts[1] - pts[0]; 35da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar mag = vec.length(); 36da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar inv = mag ? SkScalarInvert(mag) : 0; 37da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 38da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org vec.scale(inv); 39da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org matrix->setSinCos(vec.fY, vec.fX); 40da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org matrix->preTranslate(pts[0].fX, pts[0].fY); 41da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org matrix->preScale(mag, mag); 42da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 43da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 44da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* Assumes t + startOffset is on the stack and does a linear interpolation on t 45da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org between startOffset and endOffset from prevColor to curColor (for each color 46da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org component), leaving the result in component order on the stack. 47da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param range endOffset - startOffset 48da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param curColor[components] The current color components. 49da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param prevColor[components] The previous color components. 50da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org @param result The result ps function. 51da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 52da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void interpolateColorCode(SkScalar range, SkScalar* curColor, 53da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar* prevColor, int components, 54da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString* result) { 55da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Figure out how to scale each color component. 56316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com SkAutoSTMalloc<4, SkScalar> multiplierAlloc(components); 57316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com SkScalar *multiplier = multiplierAlloc.get(); 58da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for (int i = 0; i < components; i++) { 59da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org multiplier[i] = SkScalarDiv(curColor[i] - prevColor[i], range); 60da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 61da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 62da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Calculate when we no longer need to keep a copy of the input parameter t. 63da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // If the last component to use t is i, then dupInput[0..i - 1] = true 64da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // and dupInput[i .. components] = false. 65316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com SkAutoSTMalloc<4, bool> dupInputAlloc(components); 66316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com bool *dupInput = dupInputAlloc.get(); 67da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org dupInput[components - 1] = false; 68da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for (int i = components - 2; i >= 0; i--) { 69da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0; 70da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 71da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 72da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!dupInput[0] && multiplier[0] == 0) { 73da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("pop "); 74da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 75da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 76da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for (int i = 0; i < components; i++) { 77da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // If the next components needs t, make a copy. 78da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (dupInput[i]) { 79da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup "); 80da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 81da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 82da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (multiplier[i] == 0) { 83da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(prevColor[i]); 84da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 85da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 86da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (multiplier[i] != 1) { 87da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(multiplier[i]); 88da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" mul "); 89da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 90da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (prevColor[i] != 0) { 91da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(prevColor[i]); 92da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" add "); 93da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 94da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 95da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 96da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (dupInput[i]) { 97da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("exch\n"); 98da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 99da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 100da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 101da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 102da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* Generate Type 4 function code to map t=[0,1) to the passed gradient, 103da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org clamping at the edges of the range. The generated code will be of the form: 104da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (t < 0) { 105da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return colorData[0][r,g,b]; 106da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 107da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (t < info.fColorOffsets[1]) { 108da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return linearinterpolation(colorData[0][r,g,b], 109da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[1][r,g,b]); 110da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 111da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (t < info.fColorOffsets[2]) { 112da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return linearinterpolation(colorData[1][r,g,b], 113da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[2][r,g,b]); 114da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 115da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 116da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org ... } else { 117da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return colorData[info.fColorCount - 1][r,g,b]; 118da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 119da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org ... 120da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 121da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 122da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 123da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void gradientFunctionCode(const SkShader::GradientInfo& info, 124da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString* result) { 125da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org /* We want to linearly interpolate from the previous color to the next. 126da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org Scale the colors from 0..255 to 0..1 and determine the multipliers 127da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for interpolation. 128da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}. 129da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 130da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org static const int kColorComponents = 3; 131316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com typedef SkScalar ColorTuple[kColorComponents]; 132316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount); 133316338a4eb54b544409e3a98d97ea0a829aef706twiz@google.com ColorTuple *colorData = colorDataAlloc.get(); 134da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org const SkScalar scale = SkScalarInvert(SkIntToScalar(255)); 135da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for (int i = 0; i < info.fColorCount; i++) { 136da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale); 137da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale); 138da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale); 139da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 140da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 141da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Clamp the initial color. 142da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup 0 le {pop "); 143da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[0][0]); 144da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 145da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[0][1]); 146da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 147da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[0][2]); 148da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" }\n"); 149da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 150da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // The gradient colors. 151da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for (int i = 1 ; i < info.fColorCount; i++) { 152da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("{dup "); 153da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(info.fColorOffsets[i]); 154da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" le {"); 155da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (info.fColorOffsets[i - 1] != 0) { 156da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(info.fColorOffsets[i - 1]); 157da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" sub\n"); 158da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 159da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 160da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1], 161da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org colorData[i], colorData[i - 1], kColorComponents, 162da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result); 163da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("}\n"); 164da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 165da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 166da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Clamp the final color. 167da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("{pop "); 168da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[info.fColorCount - 1][0]); 169da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 170da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[info.fColorCount - 1][1]); 171da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append(" "); 172da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->appendScalar(colorData[info.fColorCount - 1][2]); 173da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 174da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org for (int i = 0 ; i < info.fColorCount; i++) { 175da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("} ifelse\n"); 176da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 177da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 178da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 179da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */ 180da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic void tileModeCode(SkShader::TileMode mode, SkString* result) { 181da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (mode == SkShader::kRepeat_TileMode) { 182da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup truncate sub\n"); // Get the fractional part. 183da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1) 184da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return; 185da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 186da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 187da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (mode == SkShader::kMirror_TileMode) { 188da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Map t mod 2 into [0, 1, 1, 0]. 189da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Code Stack 190da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->append("abs " // Map negative to positive. 191da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "dup " // t.s t.s 192da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "truncate " // t.s t 193da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "dup " // t.s t t 194da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "cvi " // t.s t T 195da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "2 mod " // t.s t (i mod 2) 196da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "1 eq " // t.s t true|false 197da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "3 1 roll " // true|false t.s t 198da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "sub " // true|false 0.s 199da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "exch " // 0.s true|false 200da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "{1 exch sub} if\n"); // 1 - 0.s|0.s 201da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 202da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 203da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 204da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic SkString linearCode(const SkShader::GradientInfo& info) { 205a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org SkString function("{pop\n"); // Just ditch the y value. 206da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 207da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 208da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 209da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 210da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 211da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 212da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic SkString radialCode(const SkShader::GradientInfo& info) { 213da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString function("{"); 214da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Find the distance from the origin. 215da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("dup " // x y y 216da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "mul " // x y^2 217da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "exch " // y^2 x 218da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "dup " // y^2 x x 219da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "mul " // y^2 x^2 220da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "add " // y^2+x^2 221da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org "sqrt\n"); // sqrt(y^2+x^2) 222da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 223da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 224da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 225da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 226da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 227da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 228da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 229da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org/* The math here is all based on the description in Two_Point_Radial_Gradient, 230da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org with one simplification, the coordinate space has been scaled so that 231da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org Dr = 1. This means we don't need to scale the entire equation by 1/Dr^2. 232da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org */ 233da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic SkString twoPointRadialCode(const SkShader::GradientInfo& info) { 234da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar dx = info.fPoint[0].fX - info.fPoint[1].fX; 235da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar dy = info.fPoint[0].fY - info.fPoint[1].fY; 236da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar sr = info.fRadius[0]; 237da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - SK_Scalar1; 238da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bool posRoot = info.fRadius[1] > info.fRadius[0]; 239da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 240da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // We start with a stack of (x y), copy it and then consume one copy in 241da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // order to calculate b and the other to calculate c. 242da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString function("{"); 243da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("2 copy "); 244da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 245da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Calculate -b and b^2. 246da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(dy); 247da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" mul exch "); 248da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(dx); 249da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" mul add "); 250da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(sr); 251da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" sub 2 mul neg dup dup mul\n"); 252da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 253da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Calculate c 254da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("4 2 roll dup mul exch dup mul add "); 255da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(SkScalarMul(sr, sr)); 256da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" sub\n"); 257da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 258da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Calculate the determinate 259da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(SkScalarMul(SkIntToScalar(4), a)); 260da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" mul sub abs sqrt\n"); 261da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 262da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // And then the final value of t. 263da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (posRoot) { 264da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("sub "); 265da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 266da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("add "); 267da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 268da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.appendScalar(SkScalarMul(SkIntToScalar(2), a)); 269da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append(" div\n"); 270da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 271da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 272da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 273da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 274da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 275da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 276da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 2776219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com/* Conical gradient shader, based on the Canvas spec for radial gradients 2786219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient 2796219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com */ 2806219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.comstatic SkString twoPointConicalCode(const SkShader::GradientInfo& info) { 2816219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX; 2826219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY; 2836219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar r0 = info.fRadius[0]; 2846219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar dr = info.fRadius[1] - info.fRadius[0]; 2856219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - 2866219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkScalarMul(dr, dr); 2876219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 2886219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // First compute t, if the pixel falls outside the cone, then we'll end 2896219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // with 'false' on the stack, otherwise we'll push 'true' with t below it 2906219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 2916219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // We start with a stack of (x y), copy it and then consume one copy in 2926219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // order to calculate b and the other to calculate c. 2936219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com SkString function("{"); 2946219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("2 copy "); 2956219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 2966219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr). 2976219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dy); 2986219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul exch "); 2996219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dx); 3006219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul add "); 3016219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(SkScalarMul(r0, dr)); 3026219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add -2 mul dup dup mul\n"); 3036219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3046219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // c = x^2 + y^2 + radius0^2 3056219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("4 2 roll dup mul exch dup mul add "); 3066219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(SkScalarMul(r0, r0)); 3076219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" sub dup 4 1 roll\n"); 3086219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3096219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // Contents of the stack at this point: c, b, b^2, c 3106219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3116219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if a = 0, then we collapse to a simpler linear case 3126219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com if (a == 0) { 3136219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3146219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // t = -c/b 3156219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("pop pop div neg dup "); 3166219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3176219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // compute radius(t) 3186219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dr); 3196219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul "); 3206219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(r0); 3216219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add\n"); 3226219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3236219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if r(t) < 0, then it's outside the cone 324ab2fe82840f37e92e7c45a36cac725c6fd2512c7rileya@google.com function.append("0 lt {pop false} {true} ifelse\n"); 3256219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3266219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com } else { 3276219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3286219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // quadratic case: the Canvas spec wants the largest 3296219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // root t for which radius(t) > 0 3306219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3316219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // compute the discriminant (b^2 - 4ac) 3326219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(SkScalarMul(SkIntToScalar(4), a)); 3336219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul sub dup\n"); 3346219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3356219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if d >= 0, proceed 3366219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("0 ge {\n"); 3376219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3386219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // an intermediate value we'll use to compute the roots: 3396219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // q = -0.5 * (b +/- sqrt(d)) 3406219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("sqrt exch dup 0 lt {exch -1 mul} if"); 3416219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add -0.5 mul dup\n"); 3426219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3436219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // first root = q / a 3446219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(a); 3456219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" div\n"); 3466219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3476219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // second root = c / q 3486219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("3 1 roll div\n"); 3496219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3506219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // put the larger root on top of the stack 3516219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("2 copy gt {exch} if\n"); 3526219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3536219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // compute radius(t) for larger root 3546219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("dup "); 3556219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dr); 3566219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul "); 3576219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(r0); 3586219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add\n"); 3596219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3606219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if r(t) > 0, we have our t, pop off the smaller root and we're done 3616219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" 0 gt {exch pop true}\n"); 3626219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3636219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // otherwise, throw out the larger one and try the smaller root 3646219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("{pop dup\n"); 3656219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(dr); 3666219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" mul "); 3676219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.appendScalar(r0); 3686219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append(" add\n"); 3696219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3706219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if r(t) < 0, push false, otherwise the smaller root is our t 371ab2fe82840f37e92e7c45a36cac725c6fd2512c7rileya@google.com function.append("0 le {pop false} {true} ifelse\n"); 3726219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("} ifelse\n"); 3736219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3746219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // d < 0, clear the stack and push false 375ab2fe82840f37e92e7c45a36cac725c6fd2512c7rileya@google.com function.append("} {pop pop pop false} ifelse\n"); 3766219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com } 3776219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3786219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // if the pixel is in the cone, proceed to compute a color 3796219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("{"); 3806219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com tileModeCode(info.fTileMode, &function); 3816219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com gradientFunctionCode(info, &function); 3826219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3836219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com // otherwise, just write black 3846219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com function.append("} {0 0 0} ifelse }"); 3856219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 3866219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com return function; 3876219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com} 3886219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com 389da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgstatic SkString sweepCode(const SkShader::GradientInfo& info) { 390da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString function("{exch atan 360 div\n"); 391da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModeCode(info.fTileMode, &function); 392da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org gradientFunctionCode(info, &function); 393da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org function.append("}"); 394da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return function; 395da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 396da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 397421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgclass SkPDFShader::State { 398421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgpublic: 399421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkShader::GradientType fType; 400421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkShader::GradientInfo fInfo; 401421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkAutoFree fColorData; 402421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkMatrix fCanvasTransform; 403421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkMatrix fShaderTransform; 404421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkIRect fBBox; 405421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 406421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkBitmap fImage; 407421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org uint32_t fPixelGeneration; 408421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkShader::TileMode fImageTileModes[2]; 409421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 410421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org explicit State(const SkShader& shader, const SkMatrix& canvasTransform, 411421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org const SkIRect& bbox); 412421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org bool operator==(const State& b) const; 413421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}; 414421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 415421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgclass SkPDFFunctionShader : public SkPDFDict, public SkPDFShader { 416421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgpublic: 417a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org explicit SkPDFFunctionShader(SkPDFShader::State* state); 41805141c23ed2731bf04e7a1ca2a03ca23014b7222robertphillips@google.com virtual ~SkPDFFunctionShader() { 419421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org if (isValid()) { 420421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org RemoveShader(this); 421421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org } 422421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org fResources.unrefAll(); 423b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org } 424da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 425386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org virtual bool isValid() { return fResources.count() > 0; } 426da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 427421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org void getResources(SkTDArray<SkPDFObject*>* resourceList) { 428421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org GetResourcesHelper(&fResources, resourceList); 429421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org } 430da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 431421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgprivate: 432421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org static SkPDFObject* RangeObject(); 433da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 434421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkTDArray<SkPDFObject*> fResources; 435421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkAutoTDelete<const SkPDFShader::State> fState; 436da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 437421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain); 438421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}; 439421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 440421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgclass SkPDFImageShader : public SkPDFStream, public SkPDFShader { 441421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgpublic: 442a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org explicit SkPDFImageShader(SkPDFShader::State* state); 44305141c23ed2731bf04e7a1ca2a03ca23014b7222robertphillips@google.com virtual ~SkPDFImageShader() { 444421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org RemoveShader(this); 445421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org fResources.unrefAll(); 446421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org } 447421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 448386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org virtual bool isValid() { return size() > 0; } 449386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org 450421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org void getResources(SkTDArray<SkPDFObject*>* resourceList) { 451421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org GetResourcesHelper(&fResources, resourceList); 452da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 453421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 454421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgprivate: 455421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkTDArray<SkPDFObject*> fResources; 456421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkAutoTDelete<const SkPDFShader::State> fState; 457421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org}; 458421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 459421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFShader::SkPDFShader() {} 460421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 461421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org// static 462421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgvoid SkPDFShader::RemoveShader(SkPDFObject* shader) { 463421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkAutoMutexAcquire lock(CanonicalShadersMutex()); 464421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org ShaderCanonicalEntry entry(shader, NULL); 465421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org int index = CanonicalShaders().find(entry); 466421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkASSERT(index >= 0); 467421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org CanonicalShaders().removeShuffle(index); 468da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 469da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 470da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org// static 471421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, 472da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org const SkMatrix& matrix, 473da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org const SkIRect& surfaceBBox) { 474421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkPDFObject* result; 475b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org SkAutoMutexAcquire lock(CanonicalShadersMutex()); 476da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAutoTDelete<State> shaderState(new State(shader, matrix, surfaceBBox)); 477da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org if (shaderState.get()->fType == SkShader::kNone_GradientType && 478da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org shaderState.get()->fImage.isNull()) { 479da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // TODO(vandebo) This drops SKComposeShader on the floor. We could 480da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // handle compose shader by pulling things up to a layer, drawing with 481da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // the first shader, applying the xfer mode and drawing again with the 482da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org // second shader, then applying the layer to the original drawing. 483da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org return NULL; 484da6c569334b5971e55dc95cb9bf85853d068e999vandebo@chromium.org } 485da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 486da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org ShaderCanonicalEntry entry(NULL, shaderState.get()); 487b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org int index = CanonicalShaders().find(entry); 488da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (index >= 0) { 489421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org result = CanonicalShaders()[index].fPDFShader; 490da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->ref(); 491da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return result; 492da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 493386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org 494386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org bool valid = false; 495da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // The PDFShader takes ownership of the shaderSate. 496421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org if (shaderState.get()->fType == SkShader::kNone_GradientType) { 497386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org SkPDFImageShader* imageShader = 498386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org new SkPDFImageShader(shaderState.detach()); 499386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org valid = imageShader->isValid(); 500386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org result = imageShader; 501421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org } else { 502421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkPDFFunctionShader* functionShader = 503421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org new SkPDFFunctionShader(shaderState.detach()); 504386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org valid = functionShader->isValid(); 505421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org result = functionShader; 506da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 507386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org if (!valid) { 508386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org delete result; 509386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return NULL; 510386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org } 511421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org entry.fPDFShader = result; 512b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org CanonicalShaders().push(entry); 513421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org return result; // return the reference that came from new. 514da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 515da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 516da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org// static 517b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.orgSkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() { 518da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // This initialization is only thread safe with gcc. 519da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders; 520da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return gCanonicalShaders; 521da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 522da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 523da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org// static 5241771cbf43d9a1334e3d870c635b4215bb888dd98digit@google.comSkBaseMutex& SkPDFShader::CanonicalShadersMutex() { 5251771cbf43d9a1334e3d870c635b4215bb888dd98digit@google.com // This initialization is only thread safe with gcc or when 5261771cbf43d9a1334e3d870c635b4215bb888dd98digit@google.com // POD-style mutex initialization is used. 5271771cbf43d9a1334e3d870c635b4215bb888dd98digit@google.com SK_DECLARE_STATIC_MUTEX(gCanonicalShadersMutex); 528da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return gCanonicalShadersMutex; 529da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 530da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 531da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org// static 532421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFObject* SkPDFFunctionShader::RangeObject() { 533da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // This initialization is only thread safe with gcc. 534da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org static SkPDFArray* range = NULL; 535b88cfe58e117ffe781e4ce2cba73cc4f7a795de7vandebo@chromium.org // This method is only used with CanonicalShadersMutex, so it's safe to 536da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // populate domain. 537da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (range == NULL) { 538da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org range = new SkPDFArray; 539da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org range->reserve(6); 540c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(0); 541c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(1); 542c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(0); 543c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(1); 544c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(0); 545c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com range->appendInt(1); 546da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 547da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return range; 548da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 549da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 550421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) 551421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org : SkPDFDict("Pattern"), 552421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org fState(state) { 553da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL; 554da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkPoint transformPoints[2]; 555da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 556da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Depending on the type of the gradient, we want to transform the 557da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // coordinate space in different ways. 558da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org const SkShader::GradientInfo* info = &fState.get()->fInfo; 559da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[0] = info->fPoint[0]; 560da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = info->fPoint[1]; 561da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org switch (fState.get()->fType) { 562da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kLinear_GradientType: 563da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &linearCode; 564da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 565da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kRadial_GradientType: 566da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = transformPoints[0]; 567da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1].fX += info->fRadius[0]; 568da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &radialCode; 569da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 570da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kRadial2_GradientType: { 571421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org // Bail out if the radii are the same. Empty fResources signals 572421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org // an error and isValid will return false. 573da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (info->fRadius[0] == info->fRadius[1]) { 574da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return; 575da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 576da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = transformPoints[0]; 577da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkScalar dr = info->fRadius[1] - info->fRadius[0]; 578da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1].fX += dr; 579da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &twoPointRadialCode; 580da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 581da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 5826219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com case SkShader::kConical_GradientType: { 5836219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com transformPoints[1] = transformPoints[0]; 5846219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com transformPoints[1].fX += SK_Scalar1; 5856219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com codeFunction = &twoPointConicalCode; 5866219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com break; 5876219728eec0819a2a28b4439d8553a70b9c232f6rileya@google.com } 588da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kSweep_GradientType: 589da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org transformPoints[1] = transformPoints[0]; 590c39c8674c94dba8b1ffe938cd99c825320cc1475vandebo@chromium.org transformPoints[1].fX += SK_Scalar1; 591da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org codeFunction = &sweepCode; 592da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 593da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kColor_GradientType: 594da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kNone_GradientType: 595020798af6780ba29156f4daec87c29ae9e4f4a12vandebo@chromium.org default: 596da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return; 597da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 598da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 599da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Move any scaling (assuming a unit gradient) or translation 600da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // (and rotation for linear gradient), of the final gradient from 601da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // info->fPoints to the matrix (updating bbox appropriately). Now 602da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // the gradient can be drawn on on the unit segment. 603da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix mapperMatrix; 604da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org unitToPointsMatrix(transformPoints, &mapperMatrix); 605da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix finalMatrix = fState.get()->fCanvasTransform; 606da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org finalMatrix.preConcat(mapperMatrix); 607da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org finalMatrix.preConcat(fState.get()->fShaderTransform); 608da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRect bbox; 609da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bbox.set(fState.get()->fBBox); 610386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org if (!transformBBox(finalMatrix, &bbox)) { 611386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return; 612386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org } 613da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 614da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRefPtr<SkPDFArray> domain = new SkPDFArray; 615da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org domain->unref(); // SkRefPtr and new both took a reference. 616da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org domain->reserve(4); 617c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fLeft); 618c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fRight); 619c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fTop); 620c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com domain->appendScalar(bbox.fBottom); 621da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 622da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkString functionCode; 623da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // The two point radial gradient further references fState.get()->fInfo 624da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // in translating from x, y coordinates to the t parameter. So, we have 625da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // to transform the points and radii according to the calculated matrix. 626da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fState.get()->fType == SkShader::kRadial2_GradientType) { 627da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkShader::GradientInfo twoPointRadialInfo = *info; 628da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix inverseMapperMatrix; 629b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org if (!mapperMatrix.invert(&inverseMapperMatrix)) { 630386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return; 631b054990307b7338e599a12d9af10eb2058b94051vandebo@chromium.org } 632da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); 633da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org twoPointRadialInfo.fRadius[0] = 634da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverseMapperMatrix.mapRadius(info->fRadius[0]); 635da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org twoPointRadialInfo.fRadius[1] = 636da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org inverseMapperMatrix.mapRadius(info->fRadius[1]); 637da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org functionCode = codeFunction(twoPointRadialInfo); 638da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 639da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org functionCode = codeFunction(*info); 640da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 641da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 642da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRefPtr<SkPDFStream> function = makePSFunction(functionCode, domain.get()); 643da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Pass one reference to fResources, SkRefPtr and new both took a reference. 644da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fResources.push(function.get()); 645da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 646da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRefPtr<SkPDFDict> pdfShader = new SkPDFDict; 647da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org pdfShader->unref(); // SkRefPtr and new both took a reference. 648c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com pdfShader->insertInt("ShadingType", 1); 649c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com pdfShader->insertName("ColorSpace", "DeviceRGB"); 650da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org pdfShader->insert("Domain", domain.get()); 651da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org pdfShader->insert("Function", new SkPDFObjRef(function.get()))->unref(); 652da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 653421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insertInt("PatternType", 2); 654421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref(); 655421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insert("Shading", pdfShader.get()); 656da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 657da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 658421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) { 659da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fState.get()->fImage.lockPixels(); 660da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 661da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix finalMatrix = fState.get()->fCanvasTransform; 662da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org finalMatrix.preConcat(fState.get()->fShaderTransform); 663da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRect surfaceBBox; 664da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org surfaceBBox.set(fState.get()->fBBox); 665386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org if (!transformBBox(finalMatrix, &surfaceBBox)) { 666386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org return; 667386dfc049baa400c13e4e98727d4c04d0242b7b8vandebo@chromium.org } 668da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 66975f97e452e8f2ee55cd2b283df7d7734f48bc2bfvandebo@chromium.org SkMatrix unflip; 67054ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org unflip.setTranslate(0, SkScalarRoundToScalar(surfaceBBox.height())); 671663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org unflip.preScale(SK_Scalar1, -SK_Scalar1); 672be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org SkISize size = SkISize::Make(SkScalarRound(surfaceBBox.width()), 673be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org SkScalarRound(surfaceBBox.height())); 674152612938020fa46999f33668027d5bc0f7afd18ctguil@chromium.org SkPDFDevice pattern(size, size, unflip); 675da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkCanvas canvas(&pattern); 676be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org canvas.translate(-surfaceBBox.fLeft, -surfaceBBox.fTop); 677be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org finalMatrix.preTranslate(surfaceBBox.fLeft, surfaceBBox.fTop); 678da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 679da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org const SkBitmap* image = &fState.get()->fImage; 68054ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org SkScalar width = SkIntToScalar(image->width()); 68154ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org SkScalar height = SkIntToScalar(image->height()); 682da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkShader::TileMode tileModes[2]; 683da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModes[0] = fState.get()->fImageTileModes[0]; 684da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModes[1] = fState.get()->fImageTileModes[1]; 685da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 686da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmap(*image, 0, 0); 687be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org SkRect patternBBox = SkRect::MakeXYWH(-surfaceBBox.fLeft, -surfaceBBox.fTop, 688be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org width, height); 689da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 690da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Tiling is implied. First we handle mirroring. 691da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode) { 692da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix xMirror; 693da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org xMirror.setScale(-1, 1); 694da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org xMirror.postTranslate(2 * width, 0); 695da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(*image, xMirror); 696da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org patternBBox.fRight += width; 697da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 698da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kMirror_TileMode) { 699da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix yMirror; 700663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org yMirror.setScale(SK_Scalar1, -SK_Scalar1); 701da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org yMirror.postTranslate(0, 2 * height); 702da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(*image, yMirror); 703da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org patternBBox.fBottom += height; 704da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 705da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode && 706da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModes[1] == SkShader::kMirror_TileMode) { 707da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix mirror; 708da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org mirror.setScale(-1, -1); 709da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org mirror.postTranslate(2 * width, 2 * height); 710da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(*image, mirror); 711da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 712da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 713da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Then handle Clamping, which requires expanding the pattern canvas to 714da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // cover the entire surfaceBBox. 715da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 716da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // If both x and y are in clamp mode, we start by filling in the corners. 717da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // (Which are just a rectangles of the corner colors.) 718da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kClamp_TileMode && 719da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org tileModes[1] == SkShader::kClamp_TileMode) { 720da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkPaint paint; 721da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRect rect; 722da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rect = SkRect::MakeLTRB(surfaceBBox.fLeft, surfaceBBox.fTop, 0, 0); 723da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 724da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org paint.setColor(image->getColor(0, 0)); 725da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 726da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 727da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 728da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rect = SkRect::MakeLTRB(width, surfaceBBox.fTop, surfaceBBox.fRight, 0); 729da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 73054ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org paint.setColor(image->getColor(image->width() - 1, 0)); 731da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 732da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 733da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 734da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rect = SkRect::MakeLTRB(width, height, surfaceBBox.fRight, 735da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org surfaceBBox.fBottom); 736da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 73754ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org paint.setColor(image->getColor(image->width() - 1, 73854ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org image->height() - 1)); 739da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 740da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 741da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 742da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rect = SkRect::MakeLTRB(surfaceBBox.fLeft, height, 0, 743da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org surfaceBBox.fBottom); 744da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (!rect.isEmpty()) { 74554ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org paint.setColor(image->getColor(0, image->height() - 1)); 746da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawRect(rect, paint); 747da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 748da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 749da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 750da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Then expand the left, right, top, then bottom. 751da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kClamp_TileMode) { 75254ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height()); 753da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (surfaceBBox.fLeft < 0) { 754da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap left; 755da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&left, subset)); 756da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 757da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix leftMatrix; 758da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org leftMatrix.setScale(-surfaceBBox.fLeft, 1); 759da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org leftMatrix.postTranslate(surfaceBBox.fLeft, 0); 760da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(left, leftMatrix); 761da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 762da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kMirror_TileMode) { 763663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org leftMatrix.postScale(SK_Scalar1, -SK_Scalar1); 764da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org leftMatrix.postTranslate(0, 2 * height); 765da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(left, leftMatrix); 766da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 767be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org patternBBox.fLeft = 0; 768da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 769da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 770da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (surfaceBBox.fRight > width) { 771da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap right; 77254ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org subset.offset(image->width() - 1, 0); 773da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&right, subset)); 774da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 775da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix rightMatrix; 776da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rightMatrix.setScale(surfaceBBox.fRight - width, 1); 777da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rightMatrix.postTranslate(width, 0); 778da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(right, rightMatrix); 779da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 780da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kMirror_TileMode) { 781663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org rightMatrix.postScale(SK_Scalar1, -SK_Scalar1); 782da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org rightMatrix.postTranslate(0, 2 * height); 783da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(right, rightMatrix); 784da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 785be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org patternBBox.fRight = surfaceBBox.width(); 786da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 787da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 788da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 789da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[1] == SkShader::kClamp_TileMode) { 79054ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1); 791da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (surfaceBBox.fTop < 0) { 792da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap top; 793da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&top, subset)); 794da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 795da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix topMatrix; 796663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org topMatrix.setScale(SK_Scalar1, -surfaceBBox.fTop); 797da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org topMatrix.postTranslate(0, surfaceBBox.fTop); 798da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(top, topMatrix); 799da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 800da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode) { 801da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org topMatrix.postScale(-1, 1); 802da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org topMatrix.postTranslate(2 * width, 0); 803da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(top, topMatrix); 804da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 805be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org patternBBox.fTop = 0; 806da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 807da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 808da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (surfaceBBox.fBottom > height) { 809da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkBitmap bottom; 81054ff85c79d5a59ad9978a91b1aec1177e54104c5vandebo@chromium.org subset.offset(0, image->height() - 1); 811da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkAssertResult(image->extractSubset(&bottom, subset)); 812da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 813da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix bottomMatrix; 814663515bc59325092c4e47f5189782bd6fcd0586avandebo@chromium.org bottomMatrix.setScale(SK_Scalar1, surfaceBBox.fBottom - height); 815da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bottomMatrix.postTranslate(0, height); 816da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(bottom, bottomMatrix); 817da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 818da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (tileModes[0] == SkShader::kMirror_TileMode) { 819da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bottomMatrix.postScale(-1, 1); 820da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org bottomMatrix.postTranslate(2 * width, 0); 821da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org canvas.drawBitmapMatrix(bottom, bottomMatrix); 822da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 823be2048a371813259c46fc2260d53ccadc4ea8133vandebo@chromium.org patternBBox.fBottom = surfaceBBox.height(); 824da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 825da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 826da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 827da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRefPtr<SkPDFArray> patternBBoxArray = new SkPDFArray; 828da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org patternBBoxArray->unref(); // SkRefPtr and new both took a reference. 829da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org patternBBoxArray->reserve(4); 830c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com patternBBoxArray->appendScalar(patternBBox.fLeft); 831c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com patternBBoxArray->appendScalar(patternBBox.fTop); 832c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com patternBBoxArray->appendScalar(patternBBox.fRight); 833c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com patternBBoxArray->appendScalar(patternBBox.fBottom); 834da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 835da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org // Put the canvas into the pattern stream (fContent). 836da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkRefPtr<SkStream> content = pattern.content(); 837da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org content->unref(); // SkRefPtr and content() both took a reference. 838188838c20818307fda770ffc395a76ea63c1c8ccvandebo@chromium.org pattern.getResources(&fResources, false); 839da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 840421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org setData(content.get()); 841421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insertName("Type", "Pattern"); 842421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insertInt("PatternType", 1); 843421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insertInt("PaintType", 1); 844421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insertInt("TilingType", 1); 845421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insert("BBox", patternBBoxArray.get()); 846421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insertScalar("XStep", patternBBox.width()); 847421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insertScalar("YStep", patternBBox.height()); 8481feb33068b1313d2647c50b90ae8e0a3d510db2ereed@google.com insert("Resources", pattern.getResourceDict()); 849421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref(); 850da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 851da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fState.get()->fImage.unlockPixels(); 852da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 853da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 854421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, 855421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkPDFArray* domain) { 856421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(), 857421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org psCode.size())); 858421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org SkPDFStream* result = new SkPDFStream(funcData.get()); 859c789cf1c6f3947283aeb34acb5a22e6204f8f6f5reed@google.com result->insertInt("FunctionType", 4); 860da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org result->insert("Domain", domain); 861f6c3ebdeb135dcdb9af225bd7af77f1fe1f92787reed@google.com result->insert("Range", RangeObject()); 862da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return result; 863da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 864da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 865421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgSkPDFShader::ShaderCanonicalEntry::ShaderCanonicalEntry(SkPDFObject* pdfShader, 866421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org const State* state) 867421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org : fPDFShader(pdfShader), 868421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org fState(state) { 869421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org} 870421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 871421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.orgbool SkPDFShader::ShaderCanonicalEntry::operator==( 872421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org const ShaderCanonicalEntry& b) const { 873421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org return fPDFShader == b.fPDFShader || 874421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org (fState != NULL && b.fState != NULL && *fState == *b.fState); 875421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org} 876421d6443fbd3a913dfa32b6492c4a2969bc6314bvandebo@chromium.org 877da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgbool SkPDFShader::State::operator==(const SkPDFShader::State& b) const { 878da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fType != b.fType || 879da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fCanvasTransform != b.fCanvasTransform || 880da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fShaderTransform != b.fShaderTransform || 881da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fBBox != b.fBBox) { 882da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 883da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 884da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 885da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fType == SkShader::kNone_GradientType) { 886da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fPixelGeneration != b.fPixelGeneration || 887da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fPixelGeneration == 0 || 888da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fImageTileModes[0] != b.fImageTileModes[0] || 889da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fImageTileModes[1] != b.fImageTileModes[1]) { 890da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 891da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 892da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 893da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fColorCount != b.fInfo.fColorCount || 894da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org memcmp(fInfo.fColors, b.fInfo.fColors, 895da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org sizeof(SkColor) * fInfo.fColorCount) != 0 || 896da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org memcmp(fInfo.fColorOffsets, b.fInfo.fColorOffsets, 897da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org sizeof(SkScalar) * fInfo.fColorCount) != 0 || 898da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fPoint[0] != b.fInfo.fPoint[0] || 899da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fTileMode != b.fInfo.fTileMode) { 900da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 901da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 902da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 903da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org switch (fType) { 904da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kLinear_GradientType: 905da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fPoint[1] != b.fInfo.fPoint[1]) { 906da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 907da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 908da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 909da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kRadial_GradientType: 910da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fRadius[0] != b.fInfo.fRadius[0]) { 911da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 912da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 913da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 914da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kRadial2_GradientType: 9154908533aef9830dc1c18552c305ed6ccb286f4f2reed@google.com case SkShader::kConical_GradientType: 916da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fInfo.fPoint[1] != b.fInfo.fPoint[1] || 917da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fRadius[0] != b.fInfo.fRadius[0] || 918da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fRadius[1] != b.fInfo.fRadius[1]) { 919da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return false; 920da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 921da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 922da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kSweep_GradientType: 923da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kNone_GradientType: 924da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org case SkShader::kColor_GradientType: 925da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org break; 926da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 927da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 928da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return true; 929da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 930da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 931da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.orgSkPDFShader::State::State(const SkShader& shader, 932da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org const SkMatrix& canvasTransform, const SkIRect& bbox) 933da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org : fCanvasTransform(canvasTransform), 934e1bc274295ec57cb3d3f01aaa8abff3b49c76c73vandebo@chromium.org fBBox(bbox), 935e1bc274295ec57cb3d3f01aaa8abff3b49c76c73vandebo@chromium.org fPixelGeneration(0) { 936da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fColorCount = 0; 937da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fColors = NULL; 938da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fColorOffsets = NULL; 939da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org shader.getLocalMatrix(&fShaderTransform); 940e1bc274295ec57cb3d3f01aaa8abff3b49c76c73vandebo@chromium.org fImageTileModes[0] = fImageTileModes[1] = SkShader::kClamp_TileMode; 941da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 942da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fType = shader.asAGradient(&fInfo); 943da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org 944da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (fType == SkShader::kNone_GradientType) { 945da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkShader::BitmapType bitmapType; 946da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkMatrix matrix; 94791f319c5dc4493384f0a52aaeef3dcc311ef6ed0rileya@google.com bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes); 948da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org if (bitmapType != SkShader::kDefault_BitmapType) { 949da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fImage.reset(); 950da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org return; 951da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 952da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org SkASSERT(matrix.isIdentity()); 953da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fPixelGeneration = fImage.getGenerationID(); 954da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } else { 955da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fColorData.set(sk_malloc_throw( 956da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); 957a5c7234e81748f76cbeede40e619351146e5286actguil@chromium.org fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); 958020798af6780ba29156f4daec87c29ae9e4f4a12vandebo@chromium.org fInfo.fColorOffsets = 959020798af6780ba29156f4daec87c29ae9e4f4a12vandebo@chromium.org reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); 960da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org shader.asAGradient(&fInfo); 961da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org } 962da912d61ede86dd3dfa8f645c6f3977f2183812bvandebo@chromium.org} 963