| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #include "SkPDFShader.h" | 10 #include "SkPDFShader.h" |
| 11 | 11 |
| 12 #include "SkCanvas.h" | 12 #include "SkCanvas.h" |
| 13 #include "SkData.h" | 13 #include "SkData.h" |
| 14 #include "SkPDFCatalog.h" | 14 #include "SkPDFCatalog.h" |
| 15 #include "SkPDFDevice.h" | 15 #include "SkPDFDevice.h" |
| 16 #include "SkPDFFormXObject.h" |
| 17 #include "SkPDFGraphicState.h" |
| 18 #include "SkPDFResourceDict.h" |
| 16 #include "SkPDFTypes.h" | 19 #include "SkPDFTypes.h" |
| 17 #include "SkPDFResourceDict.h" | |
| 18 #include "SkPDFUtils.h" | 20 #include "SkPDFUtils.h" |
| 19 #include "SkScalar.h" | 21 #include "SkScalar.h" |
| 20 #include "SkStream.h" | 22 #include "SkStream.h" |
| 21 #include "SkTemplates.h" | 23 #include "SkTemplates.h" |
| 22 #include "SkThread.h" | 24 #include "SkThread.h" |
| 25 #include "SkTSet.h" |
| 23 #include "SkTypes.h" | 26 #include "SkTypes.h" |
| 24 | 27 |
| 25 static bool transformBBox(const SkMatrix& matrix, SkRect* bbox) { | 28 static bool transformBBox(const SkMatrix& matrix, SkRect* bbox) { |
| 26 SkMatrix inverse; | 29 SkMatrix inverse; |
| 27 if (!matrix.invert(&inverse)) { | 30 if (!matrix.invert(&inverse)) { |
| 28 return false; | 31 return false; |
| 29 } | 32 } |
| 30 inverse.mapRect(bbox); | 33 inverse.mapRect(bbox); |
| 31 return true; | 34 return true; |
| 32 } | 35 } |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 tileModeCode(info.fTileMode, &function); | 395 tileModeCode(info.fTileMode, &function); |
| 393 gradientFunctionCode(info, &function); | 396 gradientFunctionCode(info, &function); |
| 394 function.append("}"); | 397 function.append("}"); |
| 395 return function; | 398 return function; |
| 396 } | 399 } |
| 397 | 400 |
| 398 class SkPDFShader::State { | 401 class SkPDFShader::State { |
| 399 public: | 402 public: |
| 400 SkShader::GradientType fType; | 403 SkShader::GradientType fType; |
| 401 SkShader::GradientInfo fInfo; | 404 SkShader::GradientInfo fInfo; |
| 402 SkAutoFree fColorData; | 405 SkAutoFree fColorData; // This provides storage for arrays in fInfo. |
| 403 SkMatrix fCanvasTransform; | 406 SkMatrix fCanvasTransform; |
| 404 SkMatrix fShaderTransform; | 407 SkMatrix fShaderTransform; |
| 405 SkIRect fBBox; | 408 SkIRect fBBox; |
| 406 | 409 |
| 407 SkBitmap fImage; | 410 SkBitmap fImage; |
| 408 uint32_t fPixelGeneration; | 411 uint32_t fPixelGeneration; |
| 409 SkShader::TileMode fImageTileModes[2]; | 412 SkShader::TileMode fImageTileModes[2]; |
| 410 | 413 |
| 411 explicit State(const SkShader& shader, const SkMatrix& canvasTransform, | 414 State(const SkShader& shader, const SkMatrix& canvasTransform, |
| 412 const SkIRect& bbox); | 415 const SkIRect& bbox); |
| 416 |
| 413 bool operator==(const State& b) const; | 417 bool operator==(const State& b) const; |
| 418 |
| 419 SkPDFShader::State* CreateAlphaToLuminosityState() const; |
| 420 SkPDFShader::State* CreateOpaqueState() const; |
| 421 |
| 422 bool GradientHasAlpha() const; |
| 423 |
| 424 private: |
| 425 State(const State& other); |
| 426 State operator=(const State& rhs) { return State(rhs); } |
| 427 void AllocateGradientInfoStorage(); |
| 414 }; | 428 }; |
| 415 | 429 |
| 416 class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader { | 430 class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader { |
| 417 public: | 431 public: |
| 418 explicit SkPDFFunctionShader(SkPDFShader::State* state); | 432 explicit SkPDFFunctionShader(SkPDFShader::State* state); |
| 419 virtual ~SkPDFFunctionShader() { | 433 virtual ~SkPDFFunctionShader() { |
| 420 if (isValid()) { | 434 if (isValid()) { |
| 421 RemoveShader(this); | 435 RemoveShader(this); |
| 422 } | 436 } |
| 423 fResources.unrefAll(); | 437 fResources.unrefAll(); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 434 | 448 |
| 435 private: | 449 private: |
| 436 static SkPDFObject* RangeObject(); | 450 static SkPDFObject* RangeObject(); |
| 437 | 451 |
| 438 SkTDArray<SkPDFObject*> fResources; | 452 SkTDArray<SkPDFObject*> fResources; |
| 439 SkAutoTDelete<const SkPDFShader::State> fState; | 453 SkAutoTDelete<const SkPDFShader::State> fState; |
| 440 | 454 |
| 441 SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain); | 455 SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain); |
| 442 }; | 456 }; |
| 443 | 457 |
| 458 /** |
| 459 * A shader for PDF gradients. This encapsulates the function shader |
| 460 * inside a tiling pattern while providing a common pattern interface. |
| 461 * The encapsulation allows the use of a SMask for transparency gradients. |
| 462 */ |
| 463 class SkPDFAlphaFunctionShader : public SkPDFStream, public SkPDFShader { |
| 464 public: |
| 465 explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state); |
| 466 virtual ~SkPDFAlphaFunctionShader() { |
| 467 if (isValid()) { |
| 468 RemoveShader(this); |
| 469 } |
| 470 } |
| 471 |
| 472 virtual bool isValid() { |
| 473 return fColorPattern.get() != NULL; |
| 474 } |
| 475 |
| 476 private: |
| 477 SkAutoTDelete<const SkPDFShader::State> fState; |
| 478 |
| 479 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
| 480 SkTSet<SkPDFObject*>* newResourceObjects) { |
| 481 fResourceDict->getResources(knownResourceObjects, |
| 482 newResourceObjects, |
| 483 true); |
| 484 } |
| 485 |
| 486 SkAutoTUnref<SkPDFObject> fColorPattern; |
| 487 SkAutoTUnref<SkPDFGraphicState> fAlphaGs; |
| 488 |
| 489 SkAutoTUnref<SkPDFResourceDict> fResourceDict; |
| 490 }; |
| 491 |
| 444 class SkPDFImageShader : public SkPDFStream, public SkPDFShader { | 492 class SkPDFImageShader : public SkPDFStream, public SkPDFShader { |
| 445 public: | 493 public: |
| 446 explicit SkPDFImageShader(SkPDFShader::State* state); | 494 explicit SkPDFImageShader(SkPDFShader::State* state); |
| 447 virtual ~SkPDFImageShader() { | 495 virtual ~SkPDFImageShader() { |
| 448 RemoveShader(this); | 496 RemoveShader(this); |
| 449 fResources.unrefAll(); | 497 fResources.unrefAll(); |
| 450 } | 498 } |
| 451 | 499 |
| 452 virtual bool isValid() { return size() > 0; } | 500 virtual bool isValid() { return size() > 0; } |
| 453 | 501 |
| 454 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, | 502 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
| 455 SkTSet<SkPDFObject*>* newResourceObjects) { | 503 SkTSet<SkPDFObject*>* newResourceObjects) { |
| 456 GetResourcesHelper(&fResources.toArray(), | 504 GetResourcesHelper(&fResources.toArray(), |
| 457 knownResourceObjects, | 505 knownResourceObjects, |
| 458 newResourceObjects); | 506 newResourceObjects); |
| 459 } | 507 } |
| 460 | 508 |
| 461 private: | 509 private: |
| 462 SkTSet<SkPDFObject*> fResources; | 510 SkTSet<SkPDFObject*> fResources; |
| 463 SkAutoTDelete<const SkPDFShader::State> fState; | 511 SkAutoTDelete<const SkPDFShader::State> fState; |
| 464 }; | 512 }; |
| 465 | 513 |
| 466 SkPDFShader::SkPDFShader() {} | 514 SkPDFShader::SkPDFShader() {} |
| 467 | 515 |
| 468 // static | 516 // static |
| 469 void SkPDFShader::RemoveShader(SkPDFObject* shader) { | 517 // This is an internal method. CanonicalShadersMutex() should already be acquire
d. |
| 470 SkAutoMutexAcquire lock(CanonicalShadersMutex()); | 518 SkPDFObject* SkPDFShader::GetPDFShaderByState(State* inState) { |
| 471 ShaderCanonicalEntry entry(shader, NULL); | 519 SkPDFObject* result; |
| 472 int index = CanonicalShaders().find(entry); | |
| 473 SkASSERT(index >= 0); | |
| 474 CanonicalShaders().removeShuffle(index); | |
| 475 } | |
| 476 | 520 |
| 477 // static | 521 SkAutoTDelete<State> shaderState(inState); |
| 478 SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, | |
| 479 const SkMatrix& matrix, | |
| 480 const SkIRect& surfaceBBox) { | |
| 481 SkPDFObject* result; | |
| 482 SkAutoMutexAcquire lock(CanonicalShadersMutex()); | |
| 483 SkAutoTDelete<State> shaderState(new State(shader, matrix, surfaceBBox)); | |
| 484 if (shaderState.get()->fType == SkShader::kNone_GradientType && | 522 if (shaderState.get()->fType == SkShader::kNone_GradientType && |
| 485 shaderState.get()->fImage.isNull()) { | 523 shaderState.get()->fImage.isNull()) { |
| 486 // TODO(vandebo) This drops SKComposeShader on the floor. We could | 524 // TODO(vandebo) This drops SKComposeShader on the floor. We could |
| 487 // handle compose shader by pulling things up to a layer, drawing with | 525 // handle compose shader by pulling things up to a layer, drawing with |
| 488 // the first shader, applying the xfer mode and drawing again with the | 526 // the first shader, applying the xfer mode and drawing again with the |
| 489 // second shader, then applying the layer to the original drawing. | 527 // second shader, then applying the layer to the original drawing. |
| 490 return NULL; | 528 return NULL; |
| 491 } | 529 } |
| 492 | 530 |
| 493 ShaderCanonicalEntry entry(NULL, shaderState.get()); | 531 ShaderCanonicalEntry entry(NULL, shaderState.get()); |
| 494 int index = CanonicalShaders().find(entry); | 532 int index = CanonicalShaders().find(entry); |
| 495 if (index >= 0) { | 533 if (index >= 0) { |
| 496 result = CanonicalShaders()[index].fPDFShader; | 534 result = CanonicalShaders()[index].fPDFShader; |
| 497 result->ref(); | 535 result->ref(); |
| 498 return result; | 536 return result; |
| 499 } | 537 } |
| 500 | 538 |
| 501 bool valid = false; | 539 bool valid = false; |
| 502 // The PDFShader takes ownership of the shaderSate. | 540 // The PDFShader takes ownership of the shaderSate. |
| 503 if (shaderState.get()->fType == SkShader::kNone_GradientType) { | 541 if (shaderState.get()->fType == SkShader::kNone_GradientType) { |
| 504 SkPDFImageShader* imageShader = | 542 SkPDFImageShader* imageShader = |
| 505 new SkPDFImageShader(shaderState.detach()); | 543 new SkPDFImageShader(shaderState.detach()); |
| 506 valid = imageShader->isValid(); | 544 valid = imageShader->isValid(); |
| 507 result = imageShader; | 545 result = imageShader; |
| 508 } else { | 546 } else { |
| 509 SkPDFFunctionShader* functionShader = | 547 if (shaderState.get()->GradientHasAlpha()) { |
| 510 new SkPDFFunctionShader(shaderState.detach()); | 548 SkPDFAlphaFunctionShader* gradientShader = |
| 511 valid = functionShader->isValid(); | 549 new SkPDFAlphaFunctionShader(shaderState.detach()); |
| 512 result = functionShader; | 550 valid = gradientShader->isValid(); |
| 551 result = gradientShader; |
| 552 } else { |
| 553 SkPDFFunctionShader* functionShader = |
| 554 new SkPDFFunctionShader(shaderState.detach()); |
| 555 valid = functionShader->isValid(); |
| 556 result = functionShader; |
| 557 } |
| 513 } | 558 } |
| 514 if (!valid) { | 559 if (!valid) { |
| 515 delete result; | 560 delete result; |
| 516 return NULL; | 561 return NULL; |
| 517 } | 562 } |
| 518 entry.fPDFShader = result; | 563 entry.fPDFShader = result; |
| 519 CanonicalShaders().push(entry); | 564 CanonicalShaders().push(entry); |
| 520 return result; // return the reference that came from new. | 565 return result; // return the reference that came from new. |
| 521 } | 566 } |
| 522 | 567 |
| 523 // static | 568 // static |
| 569 void SkPDFShader::RemoveShader(SkPDFObject* shader) { |
| 570 SkAutoMutexAcquire lock(CanonicalShadersMutex()); |
| 571 ShaderCanonicalEntry entry(shader, NULL); |
| 572 int index = CanonicalShaders().find(entry); |
| 573 SkASSERT(index >= 0); |
| 574 CanonicalShaders().removeShuffle(index); |
| 575 } |
| 576 |
| 577 // static |
| 578 SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, |
| 579 const SkMatrix& matrix, |
| 580 const SkIRect& surfaceBBox) { |
| 581 SkAutoMutexAcquire lock(CanonicalShadersMutex()); |
| 582 return GetPDFShaderByState(new State(shader, matrix, surfaceBBox)); |
| 583 } |
| 584 |
| 585 // static |
| 524 SkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() { | 586 SkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() { |
| 525 // This initialization is only thread safe with gcc. | 587 // This initialization is only thread safe with gcc. |
| 526 static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders; | 588 static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders; |
| 527 return gCanonicalShaders; | 589 return gCanonicalShaders; |
| 528 } | 590 } |
| 529 | 591 |
| 530 // static | 592 // static |
| 531 SkBaseMutex& SkPDFShader::CanonicalShadersMutex() { | 593 SkBaseMutex& SkPDFShader::CanonicalShadersMutex() { |
| 532 // This initialization is only thread safe with gcc or when | 594 // This initialization is only thread safe with gcc or when |
| 533 // POD-style mutex initialization is used. | 595 // POD-style mutex initialization is used. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 547 range->appendInt(0); | 609 range->appendInt(0); |
| 548 range->appendInt(1); | 610 range->appendInt(1); |
| 549 range->appendInt(0); | 611 range->appendInt(0); |
| 550 range->appendInt(1); | 612 range->appendInt(1); |
| 551 range->appendInt(0); | 613 range->appendInt(0); |
| 552 range->appendInt(1); | 614 range->appendInt(1); |
| 553 } | 615 } |
| 554 return range; | 616 return range; |
| 555 } | 617 } |
| 556 | 618 |
| 619 static SkPDFResourceDict* get_gradient_resource_dict( |
| 620 SkPDFObject* functionShader, |
| 621 SkPDFObject* gState) { |
| 622 SkPDFResourceDict* dict = new SkPDFResourceDict(true); |
| 623 |
| 624 if (functionShader != NULL) { |
| 625 dict->insertResourceAsRef(SkPDFResourceDict::kPattern_ResourceType, 0, |
| 626 functionShader); |
| 627 } |
| 628 if (gState != NULL) { |
| 629 dict->insertResourceAsRef(SkPDFResourceDict::kExtGState_ResourceType, 0, |
| 630 gState); |
| 631 } |
| 632 |
| 633 return dict; |
| 634 } |
| 635 |
| 636 static void populate_tiling_pattern_dict(SkPDFDict* pattern, |
| 637 SkRect& bbox, SkPDFDict* resources, |
| 638 const SkMatrix& matrix) { |
| 639 pattern->insertName("Type", "Pattern"); |
| 640 pattern->insertInt("PatternType", 1); |
| 641 pattern->insertInt("PaintType", 1); |
| 642 pattern->insertInt("TilingType", 1); |
| 643 pattern->insert("BBox", SkPDFUtils::RectToArray(bbox))->unref(); |
| 644 pattern->insertScalar("XStep", bbox.width()); |
| 645 pattern->insertScalar("YStep", bbox.height()); |
| 646 pattern->insert("Resources", resources); |
| 647 if (!matrix.isIdentity()) { |
| 648 pattern->insert("Matrix", SkPDFUtils::MatrixToArray(matrix))->unref(); |
| 649 } |
| 650 } |
| 651 |
| 652 /** |
| 653 * Creates a content stream which fills the pattern P0 across bounds. |
| 654 * The argument setup may contain any relevant PDF content stream operators |
| 655 * and will be prepended to the output content stream. |
| 656 */ |
| 657 static SkData* create_pattern_fill_content(const char setup[], SkRect& bounds) { |
| 658 SkDynamicMemoryWStream content; |
| 659 if (NULL != setup) { |
| 660 content.writeText(setup); |
| 661 } |
| 662 content.writeText("/Pattern CS/Pattern cs/P0 SCN/P0 scn\n"); |
| 663 |
| 664 SkPDFUtils::AppendRectangle(bounds, &content); |
| 665 SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPath::kEvenOdd_FillType, &cont
ent); |
| 666 |
| 667 return content.copyToData(); |
| 668 } |
| 669 |
| 670 /** |
| 671 * Creates a ExtGState with the SMask set to the luminosityShader in |
| 672 * luminosity mode. The shader pattern extends to the bbox. |
| 673 */ |
| 674 static SkPDFGraphicState* create_smask_graphic_state(SkPDFObject* luminosityShad
er, SkRect& bbox) { |
| 675 SkAutoTUnref<SkData> alphaStream(create_pattern_fill_content(NULL, bbox)); |
| 676 |
| 677 SkAutoTUnref<SkPDFResourceDict> |
| 678 resources(get_gradient_resource_dict(luminosityShader, NULL)); |
| 679 |
| 680 SkAutoTUnref<SkPDFFormXObject> alphaMask( |
| 681 new SkPDFFormXObject(alphaStream.get(), bbox, resources.get())); |
| 682 |
| 683 return SkPDFGraphicState::GetSMaskGraphicState( |
| 684 alphaMask.get(), false, |
| 685 SkPDFGraphicState::kLuminosity_SMaskMode); |
| 686 } |
| 687 |
| 688 SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state) : |
| 689 fState(state) { |
| 690 SkRect bbox; |
| 691 bbox.set(fState.get()->fBBox); |
| 692 |
| 693 fColorPattern.reset(SkPDFShader::GetPDFShaderByState(state->CreateOpaqueStat
e())); |
| 694 |
| 695 SkAutoTUnref<SkPDFObject> luminosityShader(SkPDFShader::GetPDFShaderByState( |
| 696 state->CreateAlphaToLuminosityState())); |
| 697 fAlphaGs.reset(create_smask_graphic_state(luminosityShader.get(), bbox)); |
| 698 |
| 699 fResourceDict.reset(get_gradient_resource_dict(fColorPattern.get(), fAlphaGs
.get())); |
| 700 |
| 701 SkAutoTUnref<SkData> colorStream(create_pattern_fill_content("/G0 gs", bbox)
); |
| 702 setData(colorStream.get()); |
| 703 |
| 704 populate_tiling_pattern_dict(this, bbox, fResourceDict.get(), SkMatrix::I())
; |
| 705 } |
| 706 |
| 557 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) | 707 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) |
| 558 : SkPDFDict("Pattern"), | 708 : SkPDFDict("Pattern"), |
| 559 fState(state) { | 709 fState(state) { |
| 560 SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL; | 710 SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL; |
| 561 SkPoint transformPoints[2]; | 711 SkPoint transformPoints[2]; |
| 562 | 712 |
| 563 // Depending on the type of the gradient, we want to transform the | 713 // Depending on the type of the gradient, we want to transform the |
| 564 // coordinate space in different ways. | 714 // coordinate space in different ways. |
| 565 const SkShader::GradientInfo* info = &fState.get()->fInfo; | 715 const SkShader::GradientInfo* info = &fState.get()->fInfo; |
| 566 transformPoints[0] = info->fPoint[0]; | 716 transformPoints[0] = info->fPoint[0]; |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 822 | 972 |
| 823 if (tileModes[0] == SkShader::kMirror_TileMode) { | 973 if (tileModes[0] == SkShader::kMirror_TileMode) { |
| 824 bottomMatrix.postScale(-1, 1); | 974 bottomMatrix.postScale(-1, 1); |
| 825 bottomMatrix.postTranslate(2 * width, 0); | 975 bottomMatrix.postTranslate(2 * width, 0); |
| 826 canvas.drawBitmapMatrix(bottom, bottomMatrix); | 976 canvas.drawBitmapMatrix(bottom, bottomMatrix); |
| 827 } | 977 } |
| 828 patternBBox.fBottom = surfaceBBox.height(); | 978 patternBBox.fBottom = surfaceBBox.height(); |
| 829 } | 979 } |
| 830 } | 980 } |
| 831 | 981 |
| 832 SkAutoTUnref<SkPDFArray> patternBBoxArray(new SkPDFArray); | |
| 833 patternBBoxArray->reserve(4); | |
| 834 patternBBoxArray->appendScalar(patternBBox.fLeft); | |
| 835 patternBBoxArray->appendScalar(patternBBox.fTop); | |
| 836 patternBBoxArray->appendScalar(patternBBox.fRight); | |
| 837 patternBBoxArray->appendScalar(patternBBox.fBottom); | |
| 838 | |
| 839 // Put the canvas into the pattern stream (fContent). | 982 // Put the canvas into the pattern stream (fContent). |
| 840 SkAutoTUnref<SkData> content(pattern.copyContentToData()); | 983 SkAutoTUnref<SkData> content(pattern.copyContentToData()); |
| 841 setData(content.get()); | 984 setData(content.get()); |
| 842 SkPDFResourceDict* resourceDict = pattern.getResourceDict(); | 985 SkPDFResourceDict* resourceDict = pattern.getResourceDict(); |
| 843 resourceDict->getResources(fResources, &fResources, false); | 986 resourceDict->getResources(fResources, &fResources, false); |
| 844 | 987 |
| 845 insertName("Type", "Pattern"); | 988 populate_tiling_pattern_dict(this, patternBBox, |
| 846 insertInt("PatternType", 1); | 989 pattern.getResourceDict(), finalMatrix); |
| 847 insertInt("PaintType", 1); | |
| 848 insertInt("TilingType", 1); | |
| 849 insert("BBox", patternBBoxArray.get()); | |
| 850 insertScalar("XStep", patternBBox.width()); | |
| 851 insertScalar("YStep", patternBBox.height()); | |
| 852 insert("Resources", resourceDict); | |
| 853 insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref(); | |
| 854 | 990 |
| 855 fState.get()->fImage.unlockPixels(); | 991 fState.get()->fImage.unlockPixels(); |
| 856 } | 992 } |
| 857 | 993 |
| 858 SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, | 994 SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, |
| 859 SkPDFArray* domain) { | 995 SkPDFArray* domain) { |
| 860 SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(), | 996 SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(), |
| 861 psCode.size())); | 997 psCode.size())); |
| 862 SkPDFStream* result = new SkPDFStream(funcData.get()); | 998 SkPDFStream* result = new SkPDFStream(funcData.get()); |
| 863 result->insertInt("FunctionType", 4); | 999 result->insertInt("FunctionType", 4); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 949 SkShader::BitmapType bitmapType; | 1085 SkShader::BitmapType bitmapType; |
| 950 SkMatrix matrix; | 1086 SkMatrix matrix; |
| 951 bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes); | 1087 bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes); |
| 952 if (bitmapType != SkShader::kDefault_BitmapType) { | 1088 if (bitmapType != SkShader::kDefault_BitmapType) { |
| 953 fImage.reset(); | 1089 fImage.reset(); |
| 954 return; | 1090 return; |
| 955 } | 1091 } |
| 956 SkASSERT(matrix.isIdentity()); | 1092 SkASSERT(matrix.isIdentity()); |
| 957 fPixelGeneration = fImage.getGenerationID(); | 1093 fPixelGeneration = fImage.getGenerationID(); |
| 958 } else { | 1094 } else { |
| 959 fColorData.set(sk_malloc_throw( | 1095 AllocateGradientInfoStorage(); |
| 960 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); | |
| 961 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); | |
| 962 fInfo.fColorOffsets = | |
| 963 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); | |
| 964 shader.asAGradient(&fInfo); | 1096 shader.asAGradient(&fInfo); |
| 965 } | 1097 } |
| 966 } | 1098 } |
| 1099 |
| 1100 SkPDFShader::State::State(const SkPDFShader::State& other) |
| 1101 : fType(other.fType), |
| 1102 fCanvasTransform(other.fCanvasTransform), |
| 1103 fShaderTransform(other.fShaderTransform), |
| 1104 fBBox(other.fBBox) |
| 1105 { |
| 1106 // Only gradients supported for now, since that is all that is used. |
| 1107 // If needed, image state copy constructor can be added here later. |
| 1108 SkASSERT(fType != SkShader::kNone_GradientType); |
| 1109 |
| 1110 if (fType != SkShader::kNone_GradientType) { |
| 1111 fInfo = other.fInfo; |
| 1112 |
| 1113 AllocateGradientInfoStorage(); |
| 1114 for (int i = 0; i < fInfo.fColorCount; i++) { |
| 1115 fInfo.fColors[i] = other.fInfo.fColors[i]; |
| 1116 fInfo.fColorOffsets[i] = other.fInfo.fColorOffsets[i]; |
| 1117 } |
| 1118 } |
| 1119 } |
| 1120 |
| 1121 /** |
| 1122 * Create a copy of this gradient state with alpha assigned to RGB luminousity. |
| 1123 * Only valid for gradient states! |
| 1124 */ |
| 1125 SkPDFShader::State* SkPDFShader::State::CreateAlphaToLuminosityState() const { |
| 1126 SkASSERT(fType != SkShader::kNone_GradientType); |
| 1127 |
| 1128 SkPDFShader::State* newState = new SkPDFShader::State(*this); |
| 1129 |
| 1130 for (int i = 0; i < fInfo.fColorCount; i++) { |
| 1131 SkAlpha alpha = SkColorGetA(fInfo.fColors[i]); |
| 1132 newState->fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha); |
| 1133 } |
| 1134 |
| 1135 return newState; |
| 1136 } |
| 1137 |
| 1138 /** |
| 1139 * Create a copy of this gradient state with alpha set to fully opaque |
| 1140 * Only valid for gradient states. |
| 1141 */ |
| 1142 SkPDFShader::State* SkPDFShader::State::CreateOpaqueState() const { |
| 1143 SkASSERT(fType != SkShader::kNone_GradientType); |
| 1144 |
| 1145 SkPDFShader::State* newState = new SkPDFShader::State(*this); |
| 1146 SkAlpha opaque = SkColorGetA(SK_ColorBLACK); |
| 1147 for (int i = 0; i < fInfo.fColorCount; i++) { |
| 1148 newState->fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i], opaque); |
| 1149 } |
| 1150 |
| 1151 return newState; |
| 1152 } |
| 1153 |
| 1154 /** |
| 1155 * Returns true if state is a gradient and the gradient has alpha. |
| 1156 */ |
| 1157 bool SkPDFShader::State::GradientHasAlpha() const { |
| 1158 if (fType == SkShader::kNone_GradientType) { |
| 1159 return false; |
| 1160 } |
| 1161 |
| 1162 SkAlpha opaque = SkColorGetA(SK_ColorBLACK); |
| 1163 for (int i = 0; i < fInfo.fColorCount; i++) { |
| 1164 SkAlpha alpha = SkColorGetA(fInfo.fColors[i]); |
| 1165 if (alpha != opaque) { |
| 1166 return true; |
| 1167 } |
| 1168 } |
| 1169 return false; |
| 1170 } |
| 1171 |
| 1172 void SkPDFShader::State::AllocateGradientInfoStorage() { |
| 1173 fColorData.set(sk_malloc_throw( |
| 1174 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); |
| 1175 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); |
| 1176 fInfo.fColorOffsets = |
| 1177 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCoun
t); |
| 1178 } |
| OLD | NEW |