1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "SkPDFShader.h" 11 12 #include "SkCanvas.h" 13 #include "SkData.h" 14 #include "SkPDFCatalog.h" 15 #include "SkPDFDevice.h" 16 #include "SkPDFTypes.h" 17 #include "SkPDFUtils.h" 18 #include "SkScalar.h" 19 #include "SkStream.h" 20 #include "SkTemplates.h" 21 #include "SkThread.h" 22 #include "SkTypes.h" 23 24 static void transformBBox(const SkMatrix& matrix, SkRect* bbox) { 25 SkMatrix inverse; 26 inverse.reset(); 27 matrix.invert(&inverse); 28 inverse.mapRect(bbox); 29 } 30 31 static void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) { 32 SkVector vec = pts[1] - pts[0]; 33 SkScalar mag = vec.length(); 34 SkScalar inv = mag ? SkScalarInvert(mag) : 0; 35 36 vec.scale(inv); 37 matrix->setSinCos(vec.fY, vec.fX); 38 matrix->preTranslate(pts[0].fX, pts[0].fY); 39 matrix->preScale(mag, mag); 40 } 41 42 /* Assumes t + startOffset is on the stack and does a linear interpolation on t 43 between startOffset and endOffset from prevColor to curColor (for each color 44 component), leaving the result in component order on the stack. 45 @param range endOffset - startOffset 46 @param curColor[components] The current color components. 47 @param prevColor[components] The previous color components. 48 @param result The result ps function. 49 */ 50 static void interpolateColorCode(SkScalar range, SkScalar* curColor, 51 SkScalar* prevColor, int components, 52 SkString* result) { 53 // Figure out how to scale each color component. 54 SkAutoSTMalloc<4, SkScalar> multiplierAlloc(components); 55 SkScalar *multiplier = multiplierAlloc.get(); 56 for (int i = 0; i < components; i++) { 57 multiplier[i] = SkScalarDiv(curColor[i] - prevColor[i], range); 58 } 59 60 // Calculate when we no longer need to keep a copy of the input parameter t. 61 // If the last component to use t is i, then dupInput[0..i - 1] = true 62 // and dupInput[i .. components] = false. 63 SkAutoSTMalloc<4, bool> dupInputAlloc(components); 64 bool *dupInput = dupInputAlloc.get(); 65 dupInput[components - 1] = false; 66 for (int i = components - 2; i >= 0; i--) { 67 dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0; 68 } 69 70 if (!dupInput[0] && multiplier[0] == 0) { 71 result->append("pop "); 72 } 73 74 for (int i = 0; i < components; i++) { 75 // If the next components needs t, make a copy. 76 if (dupInput[i]) { 77 result->append("dup "); 78 } 79 80 if (multiplier[i] == 0) { 81 result->appendScalar(prevColor[i]); 82 result->append(" "); 83 } else { 84 if (multiplier[i] != 1) { 85 result->appendScalar(multiplier[i]); 86 result->append(" mul "); 87 } 88 if (prevColor[i] != 0) { 89 result->appendScalar(prevColor[i]); 90 result->append(" add "); 91 } 92 } 93 94 if (dupInput[i]) { 95 result->append("exch\n"); 96 } 97 } 98 } 99 100 /* Generate Type 4 function code to map t=[0,1) to the passed gradient, 101 clamping at the edges of the range. The generated code will be of the form: 102 if (t < 0) { 103 return colorData[0][r,g,b]; 104 } else { 105 if (t < info.fColorOffsets[1]) { 106 return linearinterpolation(colorData[0][r,g,b], 107 colorData[1][r,g,b]); 108 } else { 109 if (t < info.fColorOffsets[2]) { 110 return linearinterpolation(colorData[1][r,g,b], 111 colorData[2][r,g,b]); 112 } else { 113 114 ... } else { 115 return colorData[info.fColorCount - 1][r,g,b]; 116 } 117 ... 118 } 119 } 120 */ 121 static void gradientFunctionCode(const SkShader::GradientInfo& info, 122 SkString* result) { 123 /* We want to linearly interpolate from the previous color to the next. 124 Scale the colors from 0..255 to 0..1 and determine the multipliers 125 for interpolation. 126 C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}. 127 */ 128 static const int kColorComponents = 3; 129 typedef SkScalar ColorTuple[kColorComponents]; 130 SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount); 131 ColorTuple *colorData = colorDataAlloc.get(); 132 const SkScalar scale = SkScalarInvert(SkIntToScalar(255)); 133 for (int i = 0; i < info.fColorCount; i++) { 134 colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale); 135 colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale); 136 colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale); 137 } 138 139 // Clamp the initial color. 140 result->append("dup 0 le {pop "); 141 result->appendScalar(colorData[0][0]); 142 result->append(" "); 143 result->appendScalar(colorData[0][1]); 144 result->append(" "); 145 result->appendScalar(colorData[0][2]); 146 result->append(" }\n"); 147 148 // The gradient colors. 149 for (int i = 1 ; i < info.fColorCount; i++) { 150 result->append("{dup "); 151 result->appendScalar(info.fColorOffsets[i]); 152 result->append(" le {"); 153 if (info.fColorOffsets[i - 1] != 0) { 154 result->appendScalar(info.fColorOffsets[i - 1]); 155 result->append(" sub\n"); 156 } 157 158 interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1], 159 colorData[i], colorData[i - 1], kColorComponents, 160 result); 161 result->append("}\n"); 162 } 163 164 // Clamp the final color. 165 result->append("{pop "); 166 result->appendScalar(colorData[info.fColorCount - 1][0]); 167 result->append(" "); 168 result->appendScalar(colorData[info.fColorCount - 1][1]); 169 result->append(" "); 170 result->appendScalar(colorData[info.fColorCount - 1][2]); 171 172 for (int i = 0 ; i < info.fColorCount; i++) { 173 result->append("} ifelse\n"); 174 } 175 } 176 177 /* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */ 178 static void tileModeCode(SkShader::TileMode mode, SkString* result) { 179 if (mode == SkShader::kRepeat_TileMode) { 180 result->append("dup truncate sub\n"); // Get the fractional part. 181 result->append("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1) 182 return; 183 } 184 185 if (mode == SkShader::kMirror_TileMode) { 186 // Map t mod 2 into [0, 1, 1, 0]. 187 // Code Stack 188 result->append("abs " // Map negative to positive. 189 "dup " // t.s t.s 190 "truncate " // t.s t 191 "dup " // t.s t t 192 "cvi " // t.s t T 193 "2 mod " // t.s t (i mod 2) 194 "1 eq " // t.s t true|false 195 "3 1 roll " // true|false t.s t 196 "sub " // true|false 0.s 197 "exch " // 0.s true|false 198 "{1 exch sub} if\n"); // 1 - 0.s|0.s 199 } 200 } 201 202 static SkString linearCode(const SkShader::GradientInfo& info) { 203 SkString function("{pop\n"); // Just ditch the y value. 204 tileModeCode(info.fTileMode, &function); 205 gradientFunctionCode(info, &function); 206 function.append("}"); 207 return function; 208 } 209 210 static SkString radialCode(const SkShader::GradientInfo& info) { 211 SkString function("{"); 212 // Find the distance from the origin. 213 function.append("dup " // x y y 214 "mul " // x y^2 215 "exch " // y^2 x 216 "dup " // y^2 x x 217 "mul " // y^2 x^2 218 "add " // y^2+x^2 219 "sqrt\n"); // sqrt(y^2+x^2) 220 221 tileModeCode(info.fTileMode, &function); 222 gradientFunctionCode(info, &function); 223 function.append("}"); 224 return function; 225 } 226 227 /* The math here is all based on the description in Two_Point_Radial_Gradient, 228 with one simplification, the coordinate space has been scaled so that 229 Dr = 1. This means we don't need to scale the entire equation by 1/Dr^2. 230 */ 231 static SkString twoPointRadialCode(const SkShader::GradientInfo& info) { 232 SkScalar dx = info.fPoint[0].fX - info.fPoint[1].fX; 233 SkScalar dy = info.fPoint[0].fY - info.fPoint[1].fY; 234 SkScalar sr = info.fRadius[0]; 235 SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - SK_Scalar1; 236 bool posRoot = info.fRadius[1] > info.fRadius[0]; 237 238 // We start with a stack of (x y), copy it and then consume one copy in 239 // order to calculate b and the other to calculate c. 240 SkString function("{"); 241 function.append("2 copy "); 242 243 // Calculate -b and b^2. 244 function.appendScalar(dy); 245 function.append(" mul exch "); 246 function.appendScalar(dx); 247 function.append(" mul add "); 248 function.appendScalar(sr); 249 function.append(" sub 2 mul neg dup dup mul\n"); 250 251 // Calculate c 252 function.append("4 2 roll dup mul exch dup mul add "); 253 function.appendScalar(SkScalarMul(sr, sr)); 254 function.append(" sub\n"); 255 256 // Calculate the determinate 257 function.appendScalar(SkScalarMul(SkIntToScalar(4), a)); 258 function.append(" mul sub abs sqrt\n"); 259 260 // And then the final value of t. 261 if (posRoot) { 262 function.append("sub "); 263 } else { 264 function.append("add "); 265 } 266 function.appendScalar(SkScalarMul(SkIntToScalar(2), a)); 267 function.append(" div\n"); 268 269 tileModeCode(info.fTileMode, &function); 270 gradientFunctionCode(info, &function); 271 function.append("}"); 272 return function; 273 } 274 275 static SkString sweepCode(const SkShader::GradientInfo& info) { 276 SkString function("{exch atan 360 div\n"); 277 tileModeCode(info.fTileMode, &function); 278 gradientFunctionCode(info, &function); 279 function.append("}"); 280 return function; 281 } 282 283 class SkPDFShader::State { 284 public: 285 SkShader::GradientType fType; 286 SkShader::GradientInfo fInfo; 287 SkAutoFree fColorData; 288 SkMatrix fCanvasTransform; 289 SkMatrix fShaderTransform; 290 SkIRect fBBox; 291 292 SkBitmap fImage; 293 uint32_t fPixelGeneration; 294 SkShader::TileMode fImageTileModes[2]; 295 296 explicit State(const SkShader& shader, const SkMatrix& canvasTransform, 297 const SkIRect& bbox); 298 bool operator==(const State& b) const; 299 }; 300 301 class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader { 302 public: 303 explicit SkPDFFunctionShader(SkPDFShader::State* state); 304 ~SkPDFFunctionShader() { 305 if (isValid()) { 306 RemoveShader(this); 307 } 308 fResources.unrefAll(); 309 } 310 311 bool isValid() { return fResources.count() > 0; } 312 313 void getResources(SkTDArray<SkPDFObject*>* resourceList) { 314 GetResourcesHelper(&fResources, resourceList); 315 } 316 317 private: 318 static SkPDFObject* RangeObject(); 319 320 SkTDArray<SkPDFObject*> fResources; 321 SkAutoTDelete<const SkPDFShader::State> fState; 322 323 SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain); 324 }; 325 326 class SkPDFImageShader : public SkPDFStream, public SkPDFShader { 327 public: 328 explicit SkPDFImageShader(SkPDFShader::State* state); 329 ~SkPDFImageShader() { 330 RemoveShader(this); 331 fResources.unrefAll(); 332 } 333 334 void getResources(SkTDArray<SkPDFObject*>* resourceList) { 335 GetResourcesHelper(&fResources, resourceList); 336 } 337 338 private: 339 SkTDArray<SkPDFObject*> fResources; 340 SkAutoTDelete<const SkPDFShader::State> fState; 341 }; 342 343 SkPDFShader::SkPDFShader() {} 344 345 // static 346 void SkPDFShader::RemoveShader(SkPDFObject* shader) { 347 SkAutoMutexAcquire lock(CanonicalShadersMutex()); 348 ShaderCanonicalEntry entry(shader, NULL); 349 int index = CanonicalShaders().find(entry); 350 SkASSERT(index >= 0); 351 CanonicalShaders().removeShuffle(index); 352 } 353 354 // static 355 SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, 356 const SkMatrix& matrix, 357 const SkIRect& surfaceBBox) { 358 SkPDFObject* result; 359 SkAutoMutexAcquire lock(CanonicalShadersMutex()); 360 SkAutoTDelete<State> shaderState(new State(shader, matrix, surfaceBBox)); 361 362 ShaderCanonicalEntry entry(NULL, shaderState.get()); 363 int index = CanonicalShaders().find(entry); 364 if (index >= 0) { 365 result = CanonicalShaders()[index].fPDFShader; 366 result->ref(); 367 return result; 368 } 369 // The PDFShader takes ownership of the shaderSate. 370 if (shaderState.get()->fType == SkShader::kNone_GradientType) { 371 result = new SkPDFImageShader(shaderState.detach()); 372 } else { 373 SkPDFFunctionShader* functionShader = 374 new SkPDFFunctionShader(shaderState.detach()); 375 if (!functionShader->isValid()) { 376 delete functionShader; 377 return NULL; 378 } 379 result = functionShader; 380 } 381 entry.fPDFShader = result; 382 CanonicalShaders().push(entry); 383 return result; // return the reference that came from new. 384 } 385 386 // static 387 SkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() { 388 // This initialization is only thread safe with gcc. 389 static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders; 390 return gCanonicalShaders; 391 } 392 393 // static 394 SkBaseMutex& SkPDFShader::CanonicalShadersMutex() { 395 // This initialization is only thread safe with gcc or when 396 // POD-style mutex initialization is used. 397 SK_DECLARE_STATIC_MUTEX(gCanonicalShadersMutex); 398 return gCanonicalShadersMutex; 399 } 400 401 // static 402 SkPDFObject* SkPDFFunctionShader::RangeObject() { 403 // This initialization is only thread safe with gcc. 404 static SkPDFArray* range = NULL; 405 // This method is only used with CanonicalShadersMutex, so it's safe to 406 // populate domain. 407 if (range == NULL) { 408 range = new SkPDFArray; 409 range->reserve(6); 410 range->appendInt(0); 411 range->appendInt(1); 412 range->appendInt(0); 413 range->appendInt(1); 414 range->appendInt(0); 415 range->appendInt(1); 416 } 417 return range; 418 } 419 420 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) 421 : SkPDFDict("Pattern"), 422 fState(state) { 423 SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL; 424 SkPoint transformPoints[2]; 425 426 // Depending on the type of the gradient, we want to transform the 427 // coordinate space in different ways. 428 const SkShader::GradientInfo* info = &fState.get()->fInfo; 429 transformPoints[0] = info->fPoint[0]; 430 transformPoints[1] = info->fPoint[1]; 431 switch (fState.get()->fType) { 432 case SkShader::kLinear_GradientType: 433 codeFunction = &linearCode; 434 break; 435 case SkShader::kRadial_GradientType: 436 transformPoints[1] = transformPoints[0]; 437 transformPoints[1].fX += info->fRadius[0]; 438 codeFunction = &radialCode; 439 break; 440 case SkShader::kRadial2_GradientType: { 441 // Bail out if the radii are the same. Empty fResources signals 442 // an error and isValid will return false. 443 if (info->fRadius[0] == info->fRadius[1]) { 444 return; 445 } 446 transformPoints[1] = transformPoints[0]; 447 SkScalar dr = info->fRadius[1] - info->fRadius[0]; 448 transformPoints[1].fX += dr; 449 codeFunction = &twoPointRadialCode; 450 break; 451 } 452 case SkShader::kSweep_GradientType: 453 transformPoints[1] = transformPoints[0]; 454 transformPoints[1].fX += 1; 455 codeFunction = &sweepCode; 456 break; 457 case SkShader::kColor_GradientType: 458 case SkShader::kNone_GradientType: 459 default: 460 return; 461 } 462 463 // Move any scaling (assuming a unit gradient) or translation 464 // (and rotation for linear gradient), of the final gradient from 465 // info->fPoints to the matrix (updating bbox appropriately). Now 466 // the gradient can be drawn on on the unit segment. 467 SkMatrix mapperMatrix; 468 unitToPointsMatrix(transformPoints, &mapperMatrix); 469 SkMatrix finalMatrix = fState.get()->fCanvasTransform; 470 finalMatrix.preConcat(mapperMatrix); 471 finalMatrix.preConcat(fState.get()->fShaderTransform); 472 SkRect bbox; 473 bbox.set(fState.get()->fBBox); 474 transformBBox(finalMatrix, &bbox); 475 476 SkRefPtr<SkPDFArray> domain = new SkPDFArray; 477 domain->unref(); // SkRefPtr and new both took a reference. 478 domain->reserve(4); 479 domain->appendScalar(bbox.fLeft); 480 domain->appendScalar(bbox.fRight); 481 domain->appendScalar(bbox.fTop); 482 domain->appendScalar(bbox.fBottom); 483 484 SkString functionCode; 485 // The two point radial gradient further references fState.get()->fInfo 486 // in translating from x, y coordinates to the t parameter. So, we have 487 // to transform the points and radii according to the calculated matrix. 488 if (fState.get()->fType == SkShader::kRadial2_GradientType) { 489 SkShader::GradientInfo twoPointRadialInfo = *info; 490 SkMatrix inverseMapperMatrix; 491 mapperMatrix.invert(&inverseMapperMatrix); 492 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); 493 twoPointRadialInfo.fRadius[0] = 494 inverseMapperMatrix.mapRadius(info->fRadius[0]); 495 twoPointRadialInfo.fRadius[1] = 496 inverseMapperMatrix.mapRadius(info->fRadius[1]); 497 functionCode = codeFunction(twoPointRadialInfo); 498 } else { 499 functionCode = codeFunction(*info); 500 } 501 502 SkRefPtr<SkPDFStream> function = makePSFunction(functionCode, domain.get()); 503 // Pass one reference to fResources, SkRefPtr and new both took a reference. 504 fResources.push(function.get()); 505 506 SkRefPtr<SkPDFDict> pdfShader = new SkPDFDict; 507 pdfShader->unref(); // SkRefPtr and new both took a reference. 508 pdfShader->insertInt("ShadingType", 1); 509 pdfShader->insertName("ColorSpace", "DeviceRGB"); 510 pdfShader->insert("Domain", domain.get()); 511 pdfShader->insert("Function", new SkPDFObjRef(function.get()))->unref(); 512 513 insertInt("PatternType", 2); 514 insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref(); 515 insert("Shading", pdfShader.get()); 516 } 517 518 SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) { 519 fState.get()->fImage.lockPixels(); 520 521 SkMatrix finalMatrix = fState.get()->fCanvasTransform; 522 finalMatrix.preConcat(fState.get()->fShaderTransform); 523 SkRect surfaceBBox; 524 surfaceBBox.set(fState.get()->fBBox); 525 transformBBox(finalMatrix, &surfaceBBox); 526 527 SkMatrix unflip; 528 unflip.setTranslate(0, SkScalarRound(surfaceBBox.height())); 529 unflip.preScale(SK_Scalar1, -SK_Scalar1); 530 SkISize size = SkISize::Make(SkScalarRound(surfaceBBox.width()), 531 SkScalarRound(surfaceBBox.height())); 532 SkPDFDevice pattern(size, size, unflip); 533 SkCanvas canvas(&pattern); 534 canvas.translate(-surfaceBBox.fLeft, -surfaceBBox.fTop); 535 finalMatrix.preTranslate(surfaceBBox.fLeft, surfaceBBox.fTop); 536 537 const SkBitmap* image = &fState.get()->fImage; 538 int width = image->width(); 539 int height = image->height(); 540 SkShader::TileMode tileModes[2]; 541 tileModes[0] = fState.get()->fImageTileModes[0]; 542 tileModes[1] = fState.get()->fImageTileModes[1]; 543 544 canvas.drawBitmap(*image, 0, 0); 545 SkRect patternBBox = SkRect::MakeXYWH(-surfaceBBox.fLeft, -surfaceBBox.fTop, 546 width, height); 547 548 // Tiling is implied. First we handle mirroring. 549 if (tileModes[0] == SkShader::kMirror_TileMode) { 550 SkMatrix xMirror; 551 xMirror.setScale(-1, 1); 552 xMirror.postTranslate(2 * width, 0); 553 canvas.drawBitmapMatrix(*image, xMirror); 554 patternBBox.fRight += width; 555 } 556 if (tileModes[1] == SkShader::kMirror_TileMode) { 557 SkMatrix yMirror; 558 yMirror.setScale(SK_Scalar1, -SK_Scalar1); 559 yMirror.postTranslate(0, 2 * height); 560 canvas.drawBitmapMatrix(*image, yMirror); 561 patternBBox.fBottom += height; 562 } 563 if (tileModes[0] == SkShader::kMirror_TileMode && 564 tileModes[1] == SkShader::kMirror_TileMode) { 565 SkMatrix mirror; 566 mirror.setScale(-1, -1); 567 mirror.postTranslate(2 * width, 2 * height); 568 canvas.drawBitmapMatrix(*image, mirror); 569 } 570 571 // Then handle Clamping, which requires expanding the pattern canvas to 572 // cover the entire surfaceBBox. 573 574 // If both x and y are in clamp mode, we start by filling in the corners. 575 // (Which are just a rectangles of the corner colors.) 576 if (tileModes[0] == SkShader::kClamp_TileMode && 577 tileModes[1] == SkShader::kClamp_TileMode) { 578 SkPaint paint; 579 SkRect rect; 580 rect = SkRect::MakeLTRB(surfaceBBox.fLeft, surfaceBBox.fTop, 0, 0); 581 if (!rect.isEmpty()) { 582 paint.setColor(image->getColor(0, 0)); 583 canvas.drawRect(rect, paint); 584 } 585 586 rect = SkRect::MakeLTRB(width, surfaceBBox.fTop, surfaceBBox.fRight, 0); 587 if (!rect.isEmpty()) { 588 paint.setColor(image->getColor(width - 1, 0)); 589 canvas.drawRect(rect, paint); 590 } 591 592 rect = SkRect::MakeLTRB(width, height, surfaceBBox.fRight, 593 surfaceBBox.fBottom); 594 if (!rect.isEmpty()) { 595 paint.setColor(image->getColor(width - 1, height - 1)); 596 canvas.drawRect(rect, paint); 597 } 598 599 rect = SkRect::MakeLTRB(surfaceBBox.fLeft, height, 0, 600 surfaceBBox.fBottom); 601 if (!rect.isEmpty()) { 602 paint.setColor(image->getColor(0, height - 1)); 603 canvas.drawRect(rect, paint); 604 } 605 } 606 607 // Then expand the left, right, top, then bottom. 608 if (tileModes[0] == SkShader::kClamp_TileMode) { 609 SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, height); 610 if (surfaceBBox.fLeft < 0) { 611 SkBitmap left; 612 SkAssertResult(image->extractSubset(&left, subset)); 613 614 SkMatrix leftMatrix; 615 leftMatrix.setScale(-surfaceBBox.fLeft, 1); 616 leftMatrix.postTranslate(surfaceBBox.fLeft, 0); 617 canvas.drawBitmapMatrix(left, leftMatrix); 618 619 if (tileModes[1] == SkShader::kMirror_TileMode) { 620 leftMatrix.postScale(SK_Scalar1, -SK_Scalar1); 621 leftMatrix.postTranslate(0, 2 * height); 622 canvas.drawBitmapMatrix(left, leftMatrix); 623 } 624 patternBBox.fLeft = 0; 625 } 626 627 if (surfaceBBox.fRight > width) { 628 SkBitmap right; 629 subset.offset(width - 1, 0); 630 SkAssertResult(image->extractSubset(&right, subset)); 631 632 SkMatrix rightMatrix; 633 rightMatrix.setScale(surfaceBBox.fRight - width, 1); 634 rightMatrix.postTranslate(width, 0); 635 canvas.drawBitmapMatrix(right, rightMatrix); 636 637 if (tileModes[1] == SkShader::kMirror_TileMode) { 638 rightMatrix.postScale(SK_Scalar1, -SK_Scalar1); 639 rightMatrix.postTranslate(0, 2 * height); 640 canvas.drawBitmapMatrix(right, rightMatrix); 641 } 642 patternBBox.fRight = surfaceBBox.width(); 643 } 644 } 645 646 if (tileModes[1] == SkShader::kClamp_TileMode) { 647 SkIRect subset = SkIRect::MakeXYWH(0, 0, width, 1); 648 if (surfaceBBox.fTop < 0) { 649 SkBitmap top; 650 SkAssertResult(image->extractSubset(&top, subset)); 651 652 SkMatrix topMatrix; 653 topMatrix.setScale(SK_Scalar1, -surfaceBBox.fTop); 654 topMatrix.postTranslate(0, surfaceBBox.fTop); 655 canvas.drawBitmapMatrix(top, topMatrix); 656 657 if (tileModes[0] == SkShader::kMirror_TileMode) { 658 topMatrix.postScale(-1, 1); 659 topMatrix.postTranslate(2 * width, 0); 660 canvas.drawBitmapMatrix(top, topMatrix); 661 } 662 patternBBox.fTop = 0; 663 } 664 665 if (surfaceBBox.fBottom > height) { 666 SkBitmap bottom; 667 subset.offset(0, height - 1); 668 SkAssertResult(image->extractSubset(&bottom, subset)); 669 670 SkMatrix bottomMatrix; 671 bottomMatrix.setScale(SK_Scalar1, surfaceBBox.fBottom - height); 672 bottomMatrix.postTranslate(0, height); 673 canvas.drawBitmapMatrix(bottom, bottomMatrix); 674 675 if (tileModes[0] == SkShader::kMirror_TileMode) { 676 bottomMatrix.postScale(-1, 1); 677 bottomMatrix.postTranslate(2 * width, 0); 678 canvas.drawBitmapMatrix(bottom, bottomMatrix); 679 } 680 patternBBox.fBottom = surfaceBBox.height(); 681 } 682 } 683 684 SkRefPtr<SkPDFArray> patternBBoxArray = new SkPDFArray; 685 patternBBoxArray->unref(); // SkRefPtr and new both took a reference. 686 patternBBoxArray->reserve(4); 687 patternBBoxArray->appendScalar(patternBBox.fLeft); 688 patternBBoxArray->appendScalar(patternBBox.fTop); 689 patternBBoxArray->appendScalar(patternBBox.fRight); 690 patternBBoxArray->appendScalar(patternBBox.fBottom); 691 692 // Put the canvas into the pattern stream (fContent). 693 SkRefPtr<SkStream> content = pattern.content(); 694 content->unref(); // SkRefPtr and content() both took a reference. 695 pattern.getResources(&fResources); 696 697 setData(content.get()); 698 insertName("Type", "Pattern"); 699 insertInt("PatternType", 1); 700 insertInt("PaintType", 1); 701 insertInt("TilingType", 1); 702 insert("BBox", patternBBoxArray.get()); 703 insertScalar("XStep", patternBBox.width()); 704 insertScalar("YStep", patternBBox.height()); 705 insert("Resources", pattern.getResourceDict()); 706 insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref(); 707 708 fState.get()->fImage.unlockPixels(); 709 } 710 711 SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, 712 SkPDFArray* domain) { 713 SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(), 714 psCode.size())); 715 SkPDFStream* result = new SkPDFStream(funcData.get()); 716 result->insertInt("FunctionType", 4); 717 result->insert("Domain", domain); 718 result->insert("Range", RangeObject()); 719 return result; 720 } 721 722 SkPDFShader::ShaderCanonicalEntry::ShaderCanonicalEntry(SkPDFObject* pdfShader, 723 const State* state) 724 : fPDFShader(pdfShader), 725 fState(state) { 726 } 727 728 bool SkPDFShader::ShaderCanonicalEntry::operator==( 729 const ShaderCanonicalEntry& b) const { 730 return fPDFShader == b.fPDFShader || 731 (fState != NULL && b.fState != NULL && *fState == *b.fState); 732 } 733 734 bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const { 735 if (fType != b.fType || 736 fCanvasTransform != b.fCanvasTransform || 737 fShaderTransform != b.fShaderTransform || 738 fBBox != b.fBBox) { 739 return false; 740 } 741 742 if (fType == SkShader::kNone_GradientType) { 743 if (fPixelGeneration != b.fPixelGeneration || 744 fPixelGeneration == 0 || 745 fImageTileModes[0] != b.fImageTileModes[0] || 746 fImageTileModes[1] != b.fImageTileModes[1]) { 747 return false; 748 } 749 } else { 750 if (fInfo.fColorCount != b.fInfo.fColorCount || 751 memcmp(fInfo.fColors, b.fInfo.fColors, 752 sizeof(SkColor) * fInfo.fColorCount) != 0 || 753 memcmp(fInfo.fColorOffsets, b.fInfo.fColorOffsets, 754 sizeof(SkScalar) * fInfo.fColorCount) != 0 || 755 fInfo.fPoint[0] != b.fInfo.fPoint[0] || 756 fInfo.fTileMode != b.fInfo.fTileMode) { 757 return false; 758 } 759 760 switch (fType) { 761 case SkShader::kLinear_GradientType: 762 if (fInfo.fPoint[1] != b.fInfo.fPoint[1]) { 763 return false; 764 } 765 break; 766 case SkShader::kRadial_GradientType: 767 if (fInfo.fRadius[0] != b.fInfo.fRadius[0]) { 768 return false; 769 } 770 break; 771 case SkShader::kRadial2_GradientType: 772 if (fInfo.fPoint[1] != b.fInfo.fPoint[1] || 773 fInfo.fRadius[0] != b.fInfo.fRadius[0] || 774 fInfo.fRadius[1] != b.fInfo.fRadius[1]) { 775 return false; 776 } 777 break; 778 case SkShader::kSweep_GradientType: 779 case SkShader::kNone_GradientType: 780 case SkShader::kColor_GradientType: 781 break; 782 } 783 } 784 return true; 785 } 786 787 SkPDFShader::State::State(const SkShader& shader, 788 const SkMatrix& canvasTransform, const SkIRect& bbox) 789 : fCanvasTransform(canvasTransform), 790 fBBox(bbox), 791 fPixelGeneration(0) { 792 fInfo.fColorCount = 0; 793 fInfo.fColors = NULL; 794 fInfo.fColorOffsets = NULL; 795 shader.getLocalMatrix(&fShaderTransform); 796 fImageTileModes[0] = fImageTileModes[1] = SkShader::kClamp_TileMode; 797 798 fType = shader.asAGradient(&fInfo); 799 800 if (fType == SkShader::kNone_GradientType) { 801 SkShader::BitmapType bitmapType; 802 SkMatrix matrix; 803 bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes, NULL); 804 if (bitmapType != SkShader::kDefault_BitmapType) { 805 fImage.reset(); 806 return; 807 } 808 SkASSERT(matrix.isIdentity()); 809 fPixelGeneration = fImage.getGenerationID(); 810 } else { 811 fColorData.set(sk_malloc_throw( 812 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); 813 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); 814 fInfo.fColorOffsets = 815 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); 816 shader.asAGradient(&fInfo); 817 } 818 } 819