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" |
(...skipping 487 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
498 SkPDFShader::State* CreateOpaqueState() const; | 498 SkPDFShader::State* CreateOpaqueState() const; |
499 | 499 |
500 bool GradientHasAlpha() const; | 500 bool GradientHasAlpha() const; |
501 | 501 |
502 private: | 502 private: |
503 State(const State& other); | 503 State(const State& other); |
504 State operator=(const State& rhs); | 504 State operator=(const State& rhs); |
505 void AllocateGradientInfoStorage(); | 505 void AllocateGradientInfoStorage(); |
506 }; | 506 }; |
507 | 507 |
508 static void remove_from_canon(SkPDFShader* shader) { | |
509 SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex()); | |
510 SkPDFCanon::GetCanon().removeShader(shader); | |
511 } | |
512 | |
508 class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader { | 513 class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader { |
509 SK_DECLARE_INST_COUNT(SkPDFFunctionShader) | 514 SK_DECLARE_INST_COUNT(SkPDFFunctionShader) |
510 public: | 515 public: |
511 explicit SkPDFFunctionShader(SkPDFShader::State* state); | 516 static SkPDFObject* Create(SkAutoTDelete<SkPDFShader::State>*); |
517 | |
512 virtual ~SkPDFFunctionShader() { | 518 virtual ~SkPDFFunctionShader() { |
513 SkPDFShader::RemoveFromCanonIfValid(this); | 519 remove_from_canon(this); |
514 fResources.unrefAll(); | 520 fResources.unrefAll(); |
515 } | 521 } |
516 | 522 |
517 bool isValid() SK_OVERRIDE { return fResources.count() > 0; } | |
518 SkPDFObject* toPDFObject() SK_OVERRIDE { return this; } | 523 SkPDFObject* toPDFObject() SK_OVERRIDE { return this; } |
519 | 524 |
520 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, | 525 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
521 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { | 526 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { |
522 GetResourcesHelper(&fResources, | 527 GetResourcesHelper(&fResources, |
523 knownResourceObjects, | 528 knownResourceObjects, |
524 newResourceObjects); | 529 newResourceObjects); |
525 } | 530 } |
526 | 531 |
527 private: | 532 private: |
528 static SkPDFObject* RangeObject(); | |
529 | |
530 SkTDArray<SkPDFObject*> fResources; | 533 SkTDArray<SkPDFObject*> fResources; |
531 | 534 explicit SkPDFFunctionShader(SkPDFShader::State* state) |
532 SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain); | 535 : SkPDFDict("Pattern"), SkPDFShader(state) {} |
533 typedef SkPDFDict INHERITED; | 536 typedef SkPDFDict INHERITED; |
534 }; | 537 }; |
535 | 538 |
536 /** | 539 /** |
537 * A shader for PDF gradients. This encapsulates the function shader | 540 * A shader for PDF gradients. This encapsulates the function shader |
538 * inside a tiling pattern while providing a common pattern interface. | 541 * inside a tiling pattern while providing a common pattern interface. |
539 * The encapsulation allows the use of a SMask for transparency gradients. | 542 * The encapsulation allows the use of a SMask for transparency gradients. |
540 */ | 543 */ |
541 class SkPDFAlphaFunctionShader : public SkPDFStream, public SkPDFShader { | 544 class SkPDFAlphaFunctionShader : public SkPDFStream, public SkPDFShader { |
542 public: | 545 public: |
543 explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state); | 546 static SkPDFObject* Create(SkAutoTDelete<SkPDFShader::State>*); |
544 virtual ~SkPDFAlphaFunctionShader() { | |
545 SkPDFShader::RemoveFromCanonIfValid(this); | |
546 } | |
547 | 547 |
548 bool isValid() SK_OVERRIDE { | 548 virtual ~SkPDFAlphaFunctionShader() { remove_from_canon(this); } |
549 return fColorShader.get() != NULL; | 549 |
550 } | |
551 SkPDFObject* toPDFObject() SK_OVERRIDE { return this; } | 550 SkPDFObject* toPDFObject() SK_OVERRIDE { return this; } |
552 | 551 |
553 private: | 552 private: |
554 SkPDFGraphicState* CreateSMaskGraphicState(); | 553 explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state); |
554 | |
555 static SkPDFGraphicState* CreateSMaskGraphicState( | |
556 const SkPDFShader::State&); | |
555 | 557 |
556 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, | 558 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
557 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { | 559 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { |
558 fResourceDict->getReferencedResources(knownResourceObjects, | 560 fResourceDict->getReferencedResources(knownResourceObjects, |
559 newResourceObjects, | 561 newResourceObjects, |
560 true); | 562 true); |
561 } | 563 } |
562 | 564 |
563 SkAutoTUnref<SkPDFObject> fColorShader; | 565 SkAutoTUnref<SkPDFObject> fColorShader; |
564 SkAutoTUnref<SkPDFResourceDict> fResourceDict; | 566 SkAutoTUnref<SkPDFResourceDict> fResourceDict; |
565 }; | 567 }; |
566 | 568 |
567 class SkPDFImageShader : public SkPDFStream, public SkPDFShader { | 569 class SkPDFImageShader : public SkPDFStream, public SkPDFShader { |
568 public: | 570 public: |
569 explicit SkPDFImageShader(SkPDFShader::State* state); | 571 static SkPDFObject* Create(SkAutoTDelete<SkPDFShader::State>*); |
572 | |
570 virtual ~SkPDFImageShader() { | 573 virtual ~SkPDFImageShader() { |
571 SkPDFShader::RemoveFromCanonIfValid(this); | 574 remove_from_canon(this); |
572 fResources.unrefAll(); | 575 fResources.unrefAll(); |
573 } | 576 } |
574 | 577 |
575 bool isValid() SK_OVERRIDE { return size() > 0; } | |
576 SkPDFObject* toPDFObject() SK_OVERRIDE { return this; } | 578 SkPDFObject* toPDFObject() SK_OVERRIDE { return this; } |
577 | 579 |
578 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, | 580 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, |
579 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { | 581 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { |
580 GetResourcesHelper(&fResources.toArray(), | 582 GetResourcesHelper(&fResources.toArray(), |
581 knownResourceObjects, | 583 knownResourceObjects, |
582 newResourceObjects); | 584 newResourceObjects); |
583 } | 585 } |
584 | 586 |
585 private: | 587 private: |
586 SkTSet<SkPDFObject*> fResources; | 588 SkTSet<SkPDFObject*> fResources; |
589 explicit SkPDFImageShader(SkPDFShader::State* state) : SkPDFShader(state) {} | |
587 }; | 590 }; |
588 | 591 |
589 SkPDFShader::SkPDFShader(SkPDFShader::State* s) : fShaderState(s) {} | 592 SkPDFShader::SkPDFShader(SkPDFShader::State* s) : fShaderState(s) {} |
590 | 593 |
591 SkPDFShader::~SkPDFShader() {} | 594 SkPDFShader::~SkPDFShader() {} |
592 | 595 |
593 void SkPDFShader::RemoveFromCanonIfValid(SkPDFShader* shader) { | |
594 if (shader->isValid()) { | |
595 SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex()); | |
596 SkPDFCanon::GetCanon().removeShader(shader); | |
597 } | |
598 } | |
599 | |
600 bool SkPDFShader::equals(const SkPDFShader::State& state) const { | 596 bool SkPDFShader::equals(const SkPDFShader::State& state) const { |
601 return state == *fShaderState.get(); | 597 return state == *fShaderState.get(); |
602 } | 598 } |
603 | 599 |
604 SkPDFObject* SkPDFShader::AddToCanonIfValid(SkPDFShader* shader) { | |
605 if (!shader->isValid()) { | |
606 SkDELETE(shader); | |
607 return NULL; | |
608 } | |
609 SkPDFCanon::GetCanon().addShader(shader); | |
610 return shader->toPDFObject(); | |
611 } | |
612 | |
613 // static | 600 // static |
614 SkPDFObject* SkPDFShader::GetPDFShaderByState(State* inState) { | 601 SkPDFObject* SkPDFShader::GetPDFShaderByState( |
615 SkAutoTDelete<State> state(inState); | 602 SkAutoTDelete<SkPDFShader::State>* statePtr) { |
603 SkAutoTDelete<State>& state = *statePtr; | |
mtklein
2015/01/22 21:16:32
This seems fine, but you might want to go all the
hal.canary
2015/01/22 21:46:00
Even further:
const State& state = **ownedState
mtklein
2015/01/22 21:54:21
+1
| |
616 if (state->fType == SkShader::kNone_GradientType && | 604 if (state->fType == SkShader::kNone_GradientType && |
617 state->fImage.isNull()) { | 605 state->fImage.isNull()) { |
618 // TODO(vandebo) This drops SKComposeShader on the floor. We could | 606 // TODO(vandebo) This drops SKComposeShader on the floor. We could |
619 // handle compose shader by pulling things up to a layer, drawing with | 607 // handle compose shader by pulling things up to a layer, drawing with |
620 // the first shader, applying the xfer mode and drawing again with the | 608 // the first shader, applying the xfer mode and drawing again with the |
621 // second shader, then applying the layer to the original drawing. | 609 // second shader, then applying the layer to the original drawing. |
622 return NULL; | 610 return NULL; |
623 } | 611 } |
624 | 612 |
625 SkPDFShader* pdfShader = SkPDFCanon::GetCanon().findShader(*state); | 613 SkPDFShader* pdfShader = SkPDFCanon::GetCanon().findShader(*state); |
626 if (pdfShader) { | 614 if (pdfShader) { |
627 SkASSERT(pdfShader->isValid()); | |
628 return SkRef(pdfShader->toPDFObject()); | 615 return SkRef(pdfShader->toPDFObject()); |
629 } | 616 } |
630 | 617 |
631 // The PDFShader takes ownership of the shaderSate. | 618 // The PDFShader takes ownership of the shaderSate. |
632 if (state->fType == SkShader::kNone_GradientType) { | 619 if (state->fType == SkShader::kNone_GradientType) { |
633 return SkPDFShader::AddToCanonIfValid( | 620 return SkPDFImageShader::Create(&state); |
634 SkNEW_ARGS(SkPDFImageShader, (state.detach()))); | |
635 } else if (state->GradientHasAlpha()) { | 621 } else if (state->GradientHasAlpha()) { |
636 return SkPDFShader::AddToCanonIfValid( | 622 return SkPDFAlphaFunctionShader::Create(&state); |
637 SkNEW_ARGS(SkPDFAlphaFunctionShader, (state.detach()))); | |
638 } else { | 623 } else { |
639 return SkPDFShader::AddToCanonIfValid( | 624 return SkPDFFunctionShader::Create(&state); |
640 SkNEW_ARGS(SkPDFFunctionShader, (state.detach()))); | |
641 } | 625 } |
642 } | 626 } |
643 | 627 |
644 // static | 628 // static |
645 SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, | 629 SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, |
646 const SkMatrix& matrix, | 630 const SkMatrix& matrix, |
647 const SkIRect& surfaceBBox, | 631 const SkIRect& surfaceBBox, |
648 SkScalar rasterScale) { | 632 SkScalar rasterScale) { |
649 SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex()); | 633 SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex()); |
650 return GetPDFShaderByState( | 634 SkAutoTDelete<SkPDFShader::State> state( |
651 SkNEW_ARGS(State, (shader, matrix, surfaceBBox, rasterScale))); | 635 SkNEW_ARGS(State, (shader, matrix, surfaceBBox, rasterScale))); |
652 } | 636 return GetPDFShaderByState(&state); |
653 | |
654 | |
655 // static | |
656 SkPDFObject* SkPDFFunctionShader::RangeObject() { | |
657 SkPDFCanon::GetShaderMutex().assertHeld(); | |
658 static SkPDFArray* range = NULL; | |
659 // This method is only used with CanonicalShadersMutex, so it's safe to | |
660 // populate domain. | |
661 if (range == NULL) { | |
662 range = new SkPDFArray; | |
663 range->reserve(6); | |
664 range->appendInt(0); | |
665 range->appendInt(1); | |
666 range->appendInt(0); | |
667 range->appendInt(1); | |
668 range->appendInt(0); | |
669 range->appendInt(1); | |
670 } | |
671 return range; | |
672 } | 637 } |
673 | 638 |
674 static SkPDFResourceDict* get_gradient_resource_dict( | 639 static SkPDFResourceDict* get_gradient_resource_dict( |
675 SkPDFObject* functionShader, | 640 SkPDFObject* functionShader, |
676 SkPDFObject* gState) { | 641 SkPDFObject* gState) { |
677 SkPDFResourceDict* dict = new SkPDFResourceDict(); | 642 SkPDFResourceDict* dict = new SkPDFResourceDict(); |
678 | 643 |
679 if (functionShader != NULL) { | 644 if (functionShader != NULL) { |
680 dict->insertResourceAsReference( | 645 dict->insertResourceAsReference( |
681 SkPDFResourceDict::kPattern_ResourceType, 0, functionShader); | 646 SkPDFResourceDict::kPattern_ResourceType, 0, functionShader); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
723 SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPath::kEvenOdd_FillType, | 688 SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPath::kEvenOdd_FillType, |
724 &content); | 689 &content); |
725 | 690 |
726 return content.detachAsStream(); | 691 return content.detachAsStream(); |
727 } | 692 } |
728 | 693 |
729 /** | 694 /** |
730 * Creates a ExtGState with the SMask set to the luminosityShader in | 695 * Creates a ExtGState with the SMask set to the luminosityShader in |
731 * luminosity mode. The shader pattern extends to the bbox. | 696 * luminosity mode. The shader pattern extends to the bbox. |
732 */ | 697 */ |
733 SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() { | 698 SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState( |
699 const SkPDFShader::State& state) { | |
734 SkRect bbox; | 700 SkRect bbox; |
735 bbox.set(fShaderState->fBBox); | 701 bbox.set(state.fBBox); |
736 | 702 |
737 SkAutoTUnref<SkPDFObject> luminosityShader(SkPDFShader::GetPDFShaderByState( | 703 SkAutoTDelete<SkPDFShader::State> alphaToLuminosityState( |
738 fShaderState->CreateAlphaToLuminosityState())); | 704 state.CreateAlphaToLuminosityState()); |
705 SkAutoTUnref<SkPDFObject> luminosityShader( | |
706 SkPDFShader::GetPDFShaderByState(&alphaToLuminosityState)); | |
739 | 707 |
740 SkAutoTDelete<SkStream> alphaStream(create_pattern_fill_content(-1, bbox)); | 708 SkAutoTDelete<SkStream> alphaStream(create_pattern_fill_content(-1, bbox)); |
741 | 709 |
742 SkAutoTUnref<SkPDFResourceDict> | 710 SkAutoTUnref<SkPDFResourceDict> |
743 resources(get_gradient_resource_dict(luminosityShader, NULL)); | 711 resources(get_gradient_resource_dict(luminosityShader, NULL)); |
744 | 712 |
745 SkAutoTUnref<SkPDFFormXObject> alphaMask( | 713 SkAutoTUnref<SkPDFFormXObject> alphaMask( |
746 new SkPDFFormXObject(alphaStream.get(), bbox, resources.get())); | 714 new SkPDFFormXObject(alphaStream.get(), bbox, resources.get())); |
747 | 715 |
748 return SkPDFGraphicState::GetSMaskGraphicState( | 716 return SkPDFGraphicState::GetSMaskGraphicState( |
749 alphaMask.get(), false, | 717 alphaMask.get(), false, |
750 SkPDFGraphicState::kLuminosity_SMaskMode); | 718 SkPDFGraphicState::kLuminosity_SMaskMode); |
751 } | 719 } |
752 | 720 |
753 SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state) | 721 SkPDFObject* SkPDFAlphaFunctionShader::Create( |
754 : SkPDFShader(state) { | 722 SkAutoTDelete<SkPDFShader::State>* statePtr) { |
723 SkAutoTDelete<SkPDFShader::State>& state = *statePtr; | |
755 SkRect bbox; | 724 SkRect bbox; |
756 bbox.set(fShaderState->fBBox); | 725 bbox.set(state->fBBox); |
757 | 726 |
758 fColorShader.reset( | 727 SkAutoTDelete<SkPDFShader::State> opaqueState(state->CreateOpaqueState()); |
759 SkPDFShader::GetPDFShaderByState(state->CreateOpaqueState())); | 728 |
729 SkPDFObject* colorShader = SkPDFShader::GetPDFShaderByState(&opaqueState); | |
730 if (!colorShader) { | |
731 return NULL; | |
732 } | |
760 | 733 |
761 // Create resource dict with alpha graphics state as G0 and | 734 // Create resource dict with alpha graphics state as G0 and |
762 // pattern shader as P0, then write content stream. | 735 // pattern shader as P0, then write content stream. |
763 SkAutoTUnref<SkPDFGraphicState> alphaGs(CreateSMaskGraphicState()); | 736 SkAutoTUnref<SkPDFGraphicState> alphaGs( |
764 fResourceDict.reset( | 737 SkPDFAlphaFunctionShader::CreateSMaskGraphicState(*state)); |
765 get_gradient_resource_dict(fColorShader.get(), alphaGs.get())); | 738 |
739 SkPDFAlphaFunctionShader* alphaFunctionShader = | |
740 SkNEW_ARGS(SkPDFAlphaFunctionShader, (state.detach())); | |
741 | |
742 alphaFunctionShader->fColorShader.reset(colorShader); | |
743 | |
744 alphaFunctionShader->fResourceDict.reset(get_gradient_resource_dict( | |
745 alphaFunctionShader->fColorShader.get(), alphaGs.get())); | |
766 | 746 |
767 SkAutoTDelete<SkStream> colorStream( | 747 SkAutoTDelete<SkStream> colorStream( |
768 create_pattern_fill_content(0, bbox)); | 748 create_pattern_fill_content(0, bbox)); |
769 setData(colorStream.get()); | 749 alphaFunctionShader->setData(colorStream.get()); |
mtklein
2015/01/22 21:16:33
Hey, what's the lifetime of colorStream? If SkStr
hal.canary
2015/01/22 21:46:00
duplicate() is called on the stream.
mtklein
2015/01/22 21:54:21
Interesting. Seems like we might want to switch t
| |
770 | 750 |
771 populate_tiling_pattern_dict(this, bbox, fResourceDict.get(), | 751 populate_tiling_pattern_dict(alphaFunctionShader, bbox, |
752 alphaFunctionShader->fResourceDict.get(), | |
772 SkMatrix::I()); | 753 SkMatrix::I()); |
754 SkPDFCanon::GetCanon().addShader(alphaFunctionShader); | |
755 return alphaFunctionShader; | |
773 } | 756 } |
774 | 757 |
758 SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state) | |
759 : SkPDFShader(state) {} | |
760 | |
775 // Finds affine and persp such that in = affine * persp. | 761 // Finds affine and persp such that in = affine * persp. |
776 // but it returns the inverse of perspective matrix. | 762 // but it returns the inverse of perspective matrix. |
777 static bool split_perspective(const SkMatrix in, SkMatrix* affine, | 763 static bool split_perspective(const SkMatrix in, SkMatrix* affine, |
778 SkMatrix* perspectiveInverse) { | 764 SkMatrix* perspectiveInverse) { |
779 const SkScalar p2 = in[SkMatrix::kMPersp2]; | 765 const SkScalar p2 = in[SkMatrix::kMPersp2]; |
780 | 766 |
781 if (SkScalarNearlyZero(p2)) { | 767 if (SkScalarNearlyZero(p2)) { |
782 return false; | 768 return false; |
783 } | 769 } |
784 | 770 |
(...skipping 18 matching lines...) Expand all Loading... | |
803 zero, one, zero, | 789 zero, one, zero, |
804 -p0/p2, -p1/p2, 1/p2); | 790 -p0/p2, -p1/p2, 1/p2); |
805 | 791 |
806 affine->setAll(sx - p0 * tx / p2, kx - p1 * tx / p2, tx / p2, | 792 affine->setAll(sx - p0 * tx / p2, kx - p1 * tx / p2, tx / p2, |
807 ky - p0 * ty / p2, sy - p1 * ty / p2, ty / p2, | 793 ky - p0 * ty / p2, sy - p1 * ty / p2, ty / p2, |
808 zero, zero, one); | 794 zero, zero, one); |
809 | 795 |
810 return true; | 796 return true; |
811 } | 797 } |
812 | 798 |
813 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) | 799 namespace { |
814 : SkPDFDict("Pattern"), SkPDFShader(state) { | 800 SkPDFObject* create_range_object() { |
801 SkPDFArray* range = SkNEW(SkPDFArray); | |
802 range->reserve(6); | |
803 range->appendInt(0); | |
804 range->appendInt(1); | |
805 range->appendInt(0); | |
806 range->appendInt(1); | |
807 range->appendInt(0); | |
808 range->appendInt(1); | |
809 return range; | |
810 } | |
811 | |
812 template <typename T> | |
813 void unref(T* ptr) { | |
814 ptr->unref(); | |
mtklein
2015/01/22 21:16:33
This seemed more readable as you had it all on one
hal.canary
2015/01/22 21:46:00
Done.
| |
815 } | |
816 } // namespace | |
817 | |
818 SK_DECLARE_STATIC_LAZY_PTR(SkPDFObject, | |
mtklein
2015/01/22 21:16:33
Also seemed more readable on two lines as you had
hal.canary
2015/01/22 21:46:00
Done.
| |
819 rangeObject, | |
820 create_range_object, | |
821 unref<SkPDFObject>); | |
822 | |
823 static SkPDFStream* make_ps_function(const SkString& psCode, | |
824 SkPDFArray* domain) { | |
825 SkAutoDataUnref funcData( | |
826 SkData::NewWithCopy(psCode.c_str(), psCode.size())); | |
827 SkPDFStream* result = SkNEW_ARGS(SkPDFStream, (funcData.get())); | |
828 result->insertInt("FunctionType", 4); | |
829 result->insert("Domain", domain); | |
830 result->insert("Range", rangeObject.get()); | |
831 return result; | |
832 } | |
833 | |
834 SkPDFObject* SkPDFFunctionShader::Create( | |
835 SkAutoTDelete<SkPDFShader::State>* statePtr) { | |
836 SkAutoTDelete<SkPDFShader::State>& state = *statePtr; | |
837 | |
815 SkString (*codeFunction)(const SkShader::GradientInfo& info, | 838 SkString (*codeFunction)(const SkShader::GradientInfo& info, |
816 const SkMatrix& perspectiveRemover) = NULL; | 839 const SkMatrix& perspectiveRemover) = NULL; |
817 SkPoint transformPoints[2]; | 840 SkPoint transformPoints[2]; |
818 | 841 |
819 // Depending on the type of the gradient, we want to transform the | 842 // Depending on the type of the gradient, we want to transform the |
820 // coordinate space in different ways. | 843 // coordinate space in different ways. |
821 const SkShader::GradientInfo* info = &fShaderState->fInfo; | 844 const SkShader::GradientInfo* info = &state->fInfo; |
822 transformPoints[0] = info->fPoint[0]; | 845 transformPoints[0] = info->fPoint[0]; |
823 transformPoints[1] = info->fPoint[1]; | 846 transformPoints[1] = info->fPoint[1]; |
824 switch (fShaderState->fType) { | 847 switch (state->fType) { |
825 case SkShader::kLinear_GradientType: | 848 case SkShader::kLinear_GradientType: |
826 codeFunction = &linearCode; | 849 codeFunction = &linearCode; |
827 break; | 850 break; |
828 case SkShader::kRadial_GradientType: | 851 case SkShader::kRadial_GradientType: |
829 transformPoints[1] = transformPoints[0]; | 852 transformPoints[1] = transformPoints[0]; |
830 transformPoints[1].fX += info->fRadius[0]; | 853 transformPoints[1].fX += info->fRadius[0]; |
831 codeFunction = &radialCode; | 854 codeFunction = &radialCode; |
832 break; | 855 break; |
833 case SkShader::kRadial2_GradientType: { | 856 case SkShader::kRadial2_GradientType: { |
834 // Bail out if the radii are the same. Empty fResources signals | 857 // Bail out if the radii are the same. |
835 // an error and isValid will return false. | |
836 if (info->fRadius[0] == info->fRadius[1]) { | 858 if (info->fRadius[0] == info->fRadius[1]) { |
837 return; | 859 return NULL; |
838 } | 860 } |
839 transformPoints[1] = transformPoints[0]; | 861 transformPoints[1] = transformPoints[0]; |
840 SkScalar dr = info->fRadius[1] - info->fRadius[0]; | 862 SkScalar dr = info->fRadius[1] - info->fRadius[0]; |
841 transformPoints[1].fX += dr; | 863 transformPoints[1].fX += dr; |
842 codeFunction = &twoPointRadialCode; | 864 codeFunction = &twoPointRadialCode; |
843 break; | 865 break; |
844 } | 866 } |
845 case SkShader::kConical_GradientType: { | 867 case SkShader::kConical_GradientType: { |
846 transformPoints[1] = transformPoints[0]; | 868 transformPoints[1] = transformPoints[0]; |
847 transformPoints[1].fX += SK_Scalar1; | 869 transformPoints[1].fX += SK_Scalar1; |
848 codeFunction = &twoPointConicalCode; | 870 codeFunction = &twoPointConicalCode; |
849 break; | 871 break; |
850 } | 872 } |
851 case SkShader::kSweep_GradientType: | 873 case SkShader::kSweep_GradientType: |
852 transformPoints[1] = transformPoints[0]; | 874 transformPoints[1] = transformPoints[0]; |
853 transformPoints[1].fX += SK_Scalar1; | 875 transformPoints[1].fX += SK_Scalar1; |
854 codeFunction = &sweepCode; | 876 codeFunction = &sweepCode; |
855 break; | 877 break; |
856 case SkShader::kColor_GradientType: | 878 case SkShader::kColor_GradientType: |
857 case SkShader::kNone_GradientType: | 879 case SkShader::kNone_GradientType: |
858 default: | 880 default: |
859 return; | 881 return NULL; |
860 } | 882 } |
861 | 883 |
862 // Move any scaling (assuming a unit gradient) or translation | 884 // Move any scaling (assuming a unit gradient) or translation |
863 // (and rotation for linear gradient), of the final gradient from | 885 // (and rotation for linear gradient), of the final gradient from |
864 // info->fPoints to the matrix (updating bbox appropriately). Now | 886 // info->fPoints to the matrix (updating bbox appropriately). Now |
865 // the gradient can be drawn on on the unit segment. | 887 // the gradient can be drawn on on the unit segment. |
866 SkMatrix mapperMatrix; | 888 SkMatrix mapperMatrix; |
867 unitToPointsMatrix(transformPoints, &mapperMatrix); | 889 unitToPointsMatrix(transformPoints, &mapperMatrix); |
868 | 890 |
869 SkMatrix finalMatrix = fShaderState->fCanvasTransform; | 891 SkMatrix finalMatrix = state->fCanvasTransform; |
870 finalMatrix.preConcat(fShaderState->fShaderTransform); | 892 finalMatrix.preConcat(state->fShaderTransform); |
871 finalMatrix.preConcat(mapperMatrix); | 893 finalMatrix.preConcat(mapperMatrix); |
872 | 894 |
873 // Preserves as much as posible in the final matrix, and only removes | 895 // Preserves as much as posible in the final matrix, and only removes |
874 // the perspective. The inverse of the perspective is stored in | 896 // the perspective. The inverse of the perspective is stored in |
875 // perspectiveInverseOnly matrix and has 3 useful numbers | 897 // perspectiveInverseOnly matrix and has 3 useful numbers |
876 // (p0, p1, p2), while everything else is either 0 or 1. | 898 // (p0, p1, p2), while everything else is either 0 or 1. |
877 // In this way the shader will handle it eficiently, with minimal code. | 899 // In this way the shader will handle it eficiently, with minimal code. |
878 SkMatrix perspectiveInverseOnly = SkMatrix::I(); | 900 SkMatrix perspectiveInverseOnly = SkMatrix::I(); |
879 if (finalMatrix.hasPerspective()) { | 901 if (finalMatrix.hasPerspective()) { |
880 if (!split_perspective(finalMatrix, | 902 if (!split_perspective(finalMatrix, |
881 &finalMatrix, &perspectiveInverseOnly)) { | 903 &finalMatrix, &perspectiveInverseOnly)) { |
882 return; | 904 return NULL; |
883 } | 905 } |
884 } | 906 } |
885 | 907 |
886 SkRect bbox; | 908 SkRect bbox; |
887 bbox.set(fShaderState->fBBox); | 909 bbox.set(state->fBBox); |
888 if (!inverseTransformBBox(finalMatrix, &bbox)) { | 910 if (!inverseTransformBBox(finalMatrix, &bbox)) { |
889 return; | 911 return NULL; |
890 } | 912 } |
891 | 913 |
892 SkAutoTUnref<SkPDFArray> domain(new SkPDFArray); | 914 SkAutoTUnref<SkPDFArray> domain(new SkPDFArray); |
893 domain->reserve(4); | 915 domain->reserve(4); |
894 domain->appendScalar(bbox.fLeft); | 916 domain->appendScalar(bbox.fLeft); |
895 domain->appendScalar(bbox.fRight); | 917 domain->appendScalar(bbox.fRight); |
896 domain->appendScalar(bbox.fTop); | 918 domain->appendScalar(bbox.fTop); |
897 domain->appendScalar(bbox.fBottom); | 919 domain->appendScalar(bbox.fBottom); |
898 | 920 |
899 SkString functionCode; | 921 SkString functionCode; |
900 // The two point radial gradient further references | 922 // The two point radial gradient further references |
901 // fShaderState->fInfo | 923 // state->fInfo |
902 // in translating from x, y coordinates to the t parameter. So, we have | 924 // in translating from x, y coordinates to the t parameter. So, we have |
903 // to transform the points and radii according to the calculated matrix. | 925 // to transform the points and radii according to the calculated matrix. |
904 if (fShaderState->fType == SkShader::kRadial2_GradientType) { | 926 if (state->fType == SkShader::kRadial2_GradientType) { |
905 SkShader::GradientInfo twoPointRadialInfo = *info; | 927 SkShader::GradientInfo twoPointRadialInfo = *info; |
906 SkMatrix inverseMapperMatrix; | 928 SkMatrix inverseMapperMatrix; |
907 if (!mapperMatrix.invert(&inverseMapperMatrix)) { | 929 if (!mapperMatrix.invert(&inverseMapperMatrix)) { |
908 return; | 930 return NULL; |
909 } | 931 } |
910 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); | 932 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); |
911 twoPointRadialInfo.fRadius[0] = | 933 twoPointRadialInfo.fRadius[0] = |
912 inverseMapperMatrix.mapRadius(info->fRadius[0]); | 934 inverseMapperMatrix.mapRadius(info->fRadius[0]); |
913 twoPointRadialInfo.fRadius[1] = | 935 twoPointRadialInfo.fRadius[1] = |
914 inverseMapperMatrix.mapRadius(info->fRadius[1]); | 936 inverseMapperMatrix.mapRadius(info->fRadius[1]); |
915 functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly); | 937 functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly); |
916 } else { | 938 } else { |
917 functionCode = codeFunction(*info, perspectiveInverseOnly); | 939 functionCode = codeFunction(*info, perspectiveInverseOnly); |
918 } | 940 } |
919 | 941 |
920 SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict); | 942 SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict); |
921 pdfShader->insertInt("ShadingType", 1); | 943 pdfShader->insertInt("ShadingType", 1); |
922 pdfShader->insertName("ColorSpace", "DeviceRGB"); | 944 pdfShader->insertName("ColorSpace", "DeviceRGB"); |
923 pdfShader->insert("Domain", domain.get()); | 945 pdfShader->insert("Domain", domain.get()); |
924 | 946 |
925 SkPDFStream* function = makePSFunction(functionCode, domain.get()); | 947 SkPDFStream* function = make_ps_function(functionCode, domain.get()); |
926 pdfShader->insert("Function", new SkPDFObjRef(function))->unref(); | 948 pdfShader->insert("Function", new SkPDFObjRef(function))->unref(); |
927 fResources.push(function); // Pass ownership to resource list. | |
928 | 949 |
929 insertInt("PatternType", 2); | 950 SkAutoTUnref<SkPDFArray> matrixArray( |
930 insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref(); | 951 SkPDFUtils::MatrixToArray(finalMatrix)); |
931 insert("Shading", pdfShader.get()); | 952 |
953 SkPDFFunctionShader* pdfFunctionShader = | |
954 SkNEW_ARGS(SkPDFFunctionShader, (state.detach())); | |
mtklein
2015/01/22 21:16:33
? Either way seems fine I guess, but I've seen mo
| |
955 | |
956 pdfFunctionShader->fResources.push(function); | |
957 // Pass ownership to resource list. | |
958 | |
959 pdfFunctionShader->insertInt("PatternType", 2); | |
960 pdfFunctionShader->insert("Matrix", matrixArray.get()); | |
961 pdfFunctionShader->insert("Shading", pdfShader.get()); | |
962 | |
963 SkPDFCanon::GetCanon().addShader(pdfFunctionShader); | |
964 return pdfFunctionShader; | |
932 } | 965 } |
933 | 966 |
934 SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) | 967 SkPDFObject* SkPDFImageShader::Create( |
935 : SkPDFShader(state) { | 968 SkAutoTDelete<SkPDFShader::State>* statePtr) { |
936 fShaderState->fImage.lockPixels(); | 969 SkAutoTDelete<SkPDFShader::State>& state = *statePtr; |
970 | |
971 state->fImage.lockPixels(); | |
937 | 972 |
938 // The image shader pattern cell will be drawn into a separate device | 973 // The image shader pattern cell will be drawn into a separate device |
939 // in pattern cell space (no scaling on the bitmap, though there may be | 974 // in pattern cell space (no scaling on the bitmap, though there may be |
940 // translations so that all content is in the device, coordinates > 0). | 975 // translations so that all content is in the device, coordinates > 0). |
941 | 976 |
942 // Map clip bounds to shader space to ensure the device is large enough | 977 // Map clip bounds to shader space to ensure the device is large enough |
943 // to handle fake clamping. | 978 // to handle fake clamping. |
944 SkMatrix finalMatrix = fShaderState->fCanvasTransform; | 979 SkMatrix finalMatrix = state->fCanvasTransform; |
945 finalMatrix.preConcat(fShaderState->fShaderTransform); | 980 finalMatrix.preConcat(state->fShaderTransform); |
946 SkRect deviceBounds; | 981 SkRect deviceBounds; |
947 deviceBounds.set(fShaderState->fBBox); | 982 deviceBounds.set(state->fBBox); |
948 if (!inverseTransformBBox(finalMatrix, &deviceBounds)) { | 983 if (!inverseTransformBBox(finalMatrix, &deviceBounds)) { |
949 return; | 984 return NULL; |
950 } | 985 } |
951 | 986 |
952 const SkBitmap* image = &fShaderState->fImage; | 987 const SkBitmap* image = &state->fImage; |
953 SkRect bitmapBounds; | 988 SkRect bitmapBounds; |
954 image->getBounds(&bitmapBounds); | 989 image->getBounds(&bitmapBounds); |
955 | 990 |
956 // For tiling modes, the bounds should be extended to include the bitmap, | 991 // For tiling modes, the bounds should be extended to include the bitmap, |
957 // otherwise the bitmap gets clipped out and the shader is empty and awful. | 992 // otherwise the bitmap gets clipped out and the shader is empty and awful. |
958 // For clamp modes, we're only interested in the clip region, whether | 993 // For clamp modes, we're only interested in the clip region, whether |
959 // or not the main bitmap is in it. | 994 // or not the main bitmap is in it. |
960 SkShader::TileMode tileModes[2]; | 995 SkShader::TileMode tileModes[2]; |
961 tileModes[0] = fShaderState->fImageTileModes[0]; | 996 tileModes[0] = state->fImageTileModes[0]; |
962 tileModes[1] = fShaderState->fImageTileModes[1]; | 997 tileModes[1] = state->fImageTileModes[1]; |
963 if (tileModes[0] != SkShader::kClamp_TileMode || | 998 if (tileModes[0] != SkShader::kClamp_TileMode || |
964 tileModes[1] != SkShader::kClamp_TileMode) { | 999 tileModes[1] != SkShader::kClamp_TileMode) { |
965 deviceBounds.join(bitmapBounds); | 1000 deviceBounds.join(bitmapBounds); |
966 } | 1001 } |
967 | 1002 |
968 SkMatrix unflip; | 1003 SkMatrix unflip; |
969 unflip.setTranslate(0, SkScalarRoundToScalar(deviceBounds.height())); | 1004 unflip.setTranslate(0, SkScalarRoundToScalar(deviceBounds.height())); |
970 unflip.preScale(SK_Scalar1, -SK_Scalar1); | 1005 unflip.preScale(SK_Scalar1, -SK_Scalar1); |
971 SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()), | 1006 SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()), |
972 SkScalarRoundToInt(deviceBounds.height())); | 1007 SkScalarRoundToInt(deviceBounds.height())); |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1125 bottomMatrix.postScale(-1, 1); | 1160 bottomMatrix.postScale(-1, 1); |
1126 bottomMatrix.postTranslate(2 * width, 0); | 1161 bottomMatrix.postTranslate(2 * width, 0); |
1127 drawBitmapMatrix(&canvas, bottom, bottomMatrix); | 1162 drawBitmapMatrix(&canvas, bottom, bottomMatrix); |
1128 } | 1163 } |
1129 patternBBox.fBottom = deviceBounds.height(); | 1164 patternBBox.fBottom = deviceBounds.height(); |
1130 } | 1165 } |
1131 } | 1166 } |
1132 | 1167 |
1133 // Put the canvas into the pattern stream (fContent). | 1168 // Put the canvas into the pattern stream (fContent). |
1134 SkAutoTDelete<SkStream> content(pattern.content()); | 1169 SkAutoTDelete<SkStream> content(pattern.content()); |
1135 setData(content.get()); | 1170 |
1171 SkPDFImageShader* imageShader = | |
1172 SkNEW_ARGS(SkPDFImageShader, (state.detach())); | |
mtklein
2015/01/22 21:16:33
ditto
| |
1173 imageShader->setData(content.get()); | |
1174 | |
1136 SkPDFResourceDict* resourceDict = pattern.getResourceDict(); | 1175 SkPDFResourceDict* resourceDict = pattern.getResourceDict(); |
1137 resourceDict->getReferencedResources(fResources, &fResources, false); | 1176 resourceDict->getReferencedResources(imageShader->fResources, |
1177 &imageShader->fResources, false); | |
1138 | 1178 |
1139 populate_tiling_pattern_dict(this, patternBBox, | 1179 populate_tiling_pattern_dict(imageShader, patternBBox, |
1140 pattern.getResourceDict(), finalMatrix); | 1180 pattern.getResourceDict(), finalMatrix); |
1141 | 1181 |
1142 fShaderState->fImage.unlockPixels(); | 1182 imageShader->fShaderState->fImage.unlockPixels(); |
1143 } | |
1144 | 1183 |
1145 SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, SkPDFAr ray* domain) { | 1184 SkPDFCanon::GetCanon().addShader(imageShader); |
1146 SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(), psCode.size())) ; | 1185 return imageShader; |
1147 SkPDFStream* result = new SkPDFStream(funcData.get()); | |
1148 result->insertInt("FunctionType", 4); | |
1149 result->insert("Domain", domain); | |
1150 result->insert("Range", RangeObject()); | |
1151 return result; | |
1152 } | 1186 } |
1153 | 1187 |
1154 bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const { | 1188 bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const { |
1155 if (fType != b.fType || | 1189 if (fType != b.fType || |
1156 fCanvasTransform != b.fCanvasTransform || | 1190 fCanvasTransform != b.fCanvasTransform || |
1157 fShaderTransform != b.fShaderTransform || | 1191 fShaderTransform != b.fShaderTransform || |
1158 fBBox != b.fBBox) { | 1192 fBBox != b.fBBox) { |
1159 return false; | 1193 return false; |
1160 } | 1194 } |
1161 | 1195 |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1334 return false; | 1368 return false; |
1335 } | 1369 } |
1336 | 1370 |
1337 void SkPDFShader::State::AllocateGradientInfoStorage() { | 1371 void SkPDFShader::State::AllocateGradientInfoStorage() { |
1338 fColorData.set(sk_malloc_throw( | 1372 fColorData.set(sk_malloc_throw( |
1339 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); | 1373 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); |
1340 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); | 1374 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); |
1341 fInfo.fColorOffsets = | 1375 fInfo.fColorOffsets = |
1342 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); | 1376 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); |
1343 } | 1377 } |
OLD | NEW |