Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: src/pdf/SkPDFShader.cpp

Issue 842253003: SkPDFCanon (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« src/pdf/SkPDFShader.h ('K') | « src/pdf/SkPDFShader.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "SkData.h" 12 #include "SkData.h"
13 #include "SkPDFCanon.h"
13 #include "SkPDFCatalog.h" 14 #include "SkPDFCatalog.h"
14 #include "SkPDFDevice.h" 15 #include "SkPDFDevice.h"
15 #include "SkPDFFormXObject.h" 16 #include "SkPDFFormXObject.h"
16 #include "SkPDFGraphicState.h" 17 #include "SkPDFGraphicState.h"
17 #include "SkPDFResourceDict.h" 18 #include "SkPDFResourceDict.h"
18 #include "SkPDFUtils.h" 19 #include "SkPDFUtils.h"
19 #include "SkScalar.h" 20 #include "SkScalar.h"
20 #include "SkStream.h" 21 #include "SkStream.h"
21 #include "SkTemplates.h" 22 #include "SkTemplates.h"
22 #include "SkThread.h" 23 #include "SkThread.h"
(...skipping 445 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 function.append("}"); 469 function.append("}");
469 return function; 470 return function;
470 } 471 }
471 472
472 static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatri x& matrix) { 473 static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatri x& matrix) {
473 SkAutoCanvasRestore acr(canvas, true); 474 SkAutoCanvasRestore acr(canvas, true);
474 canvas->concat(matrix); 475 canvas->concat(matrix);
475 canvas->drawBitmap(bm, 0, 0); 476 canvas->drawBitmap(bm, 0, 0);
476 } 477 }
477 478
478 class SkPDFShader::State { 479 class SkPDFShaderState {
479 public: 480 public:
480 SkShader::GradientType fType; 481 SkShader::GradientType fType;
481 SkShader::GradientInfo fInfo; 482 SkShader::GradientInfo fInfo;
482 SkAutoFree fColorData; // This provides storage for arrays in fInfo. 483 SkAutoFree fColorData; // This provides storage for arrays in fInfo.
483 SkMatrix fCanvasTransform; 484 SkMatrix fCanvasTransform;
484 SkMatrix fShaderTransform; 485 SkMatrix fShaderTransform;
485 SkIRect fBBox; 486 SkIRect fBBox;
486 487
487 SkBitmap fImage; 488 SkBitmap fImage;
488 uint32_t fPixelGeneration; 489 uint32_t fPixelGeneration;
489 SkShader::TileMode fImageTileModes[2]; 490 SkShader::TileMode fImageTileModes[2];
490 491
491 State(const SkShader& shader, const SkMatrix& canvasTransform, 492 SkPDFShaderState(const SkShader& shader,
492 const SkIRect& bbox); 493 const SkMatrix& canvasTransform,
494 const SkIRect& bbox);
493 495
494 bool operator==(const State& b) const; 496 bool operator==(const SkPDFShaderState& b) const;
495 497
496 SkPDFShader::State* CreateAlphaToLuminosityState() const; 498 SkPDFShaderState* CreateAlphaToLuminosityState() const;
497 SkPDFShader::State* CreateOpaqueState() const; 499 SkPDFShaderState* CreateOpaqueState() const;
498 500
499 bool GradientHasAlpha() const; 501 bool GradientHasAlpha() const;
500 502
501 private: 503 private:
502 State(const State& other); 504 SkPDFShaderState(const SkPDFShaderState& other);
503 State operator=(const State& rhs); 505 SkPDFShaderState operator=(const SkPDFShaderState& rhs);
504 void AllocateGradientInfoStorage(); 506 void AllocateGradientInfoStorage();
505 }; 507 };
506 508
507 class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader { 509 class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader {
508 SK_DECLARE_INST_COUNT(SkPDFFunctionShader) 510 SK_DECLARE_INST_COUNT(SkPDFFunctionShader)
509 public: 511 public:
510 explicit SkPDFFunctionShader(SkPDFShader::State* state); 512 explicit SkPDFFunctionShader(SkPDFShaderState* state);
511 virtual ~SkPDFFunctionShader() { 513 virtual ~SkPDFFunctionShader() {
512 if (isValid()) { 514 if (isValid()) {
513 RemoveShader(this); 515 SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
516 SkPDFCanon::GetCanon().removeShader(this);
514 } 517 }
515 fResources.unrefAll(); 518 fResources.unrefAll();
516 } 519 }
517 520
518 bool isValid() SK_OVERRIDE { return fResources.count() > 0; } 521 bool isValid() SK_OVERRIDE { return fResources.count() > 0; }
519 522
523 virtual SkPDFObject* toPDFObject() SK_OVERRIDE {
524 return this;
525 }
526
520 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 527 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
521 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { 528 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE {
522 GetResourcesHelper(&fResources, 529 GetResourcesHelper(&fResources,
523 knownResourceObjects, 530 knownResourceObjects,
524 newResourceObjects); 531 newResourceObjects);
525 } 532 }
526 533
527 private: 534 private:
528 static SkPDFObject* RangeObject(); 535 static SkPDFObject* RangeObject();
529 536
530 SkTDArray<SkPDFObject*> fResources; 537 SkTDArray<SkPDFObject*> fResources;
531 SkAutoTDelete<const SkPDFShader::State> fState;
532 538
533 SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain); 539 SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain);
534 typedef SkPDFDict INHERITED; 540 typedef SkPDFDict INHERITED;
535 }; 541 };
536 542
537 /** 543 /**
538 * A shader for PDF gradients. This encapsulates the function shader 544 * A shader for PDF gradients. This encapsulates the function shader
539 * inside a tiling pattern while providing a common pattern interface. 545 * inside a tiling pattern while providing a common pattern interface.
540 * The encapsulation allows the use of a SMask for transparency gradients. 546 * The encapsulation allows the use of a SMask for transparency gradients.
541 */ 547 */
542 class SkPDFAlphaFunctionShader : public SkPDFStream, public SkPDFShader { 548 class SkPDFAlphaFunctionShader : public SkPDFStream, public SkPDFShader {
543 public: 549 public:
544 explicit SkPDFAlphaFunctionShader(SkPDFShader::State* state); 550 explicit SkPDFAlphaFunctionShader(SkPDFShaderState* state);
545 virtual ~SkPDFAlphaFunctionShader() { 551 virtual ~SkPDFAlphaFunctionShader() {
546 if (isValid()) { 552 if (isValid()) {
547 RemoveShader(this); 553 SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
554 SkPDFCanon::GetCanon().removeShader(this);
548 } 555 }
549 } 556 }
550 557
551 bool isValid() SK_OVERRIDE { 558 bool isValid() SK_OVERRIDE {
552 return fColorShader.get() != NULL; 559 return fColorShader.get() != NULL;
553 } 560 }
554 561
562 virtual SkPDFObject* toPDFObject() SK_OVERRIDE {
563 return this;
564 }
565
555 private: 566 private:
556 SkAutoTDelete<const SkPDFShader::State> fState;
557
558 SkPDFGraphicState* CreateSMaskGraphicState(); 567 SkPDFGraphicState* CreateSMaskGraphicState();
559 568
560 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 569 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
561 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { 570 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE {
562 fResourceDict->getReferencedResources(knownResourceObjects, 571 fResourceDict->getReferencedResources(knownResourceObjects,
563 newResourceObjects, 572 newResourceObjects,
564 true); 573 true);
565 } 574 }
566 575
567 SkAutoTUnref<SkPDFObject> fColorShader; 576 SkAutoTUnref<SkPDFObject> fColorShader;
568 SkAutoTUnref<SkPDFResourceDict> fResourceDict; 577 SkAutoTUnref<SkPDFResourceDict> fResourceDict;
569 }; 578 };
570 579
571 class SkPDFImageShader : public SkPDFStream, public SkPDFShader { 580 class SkPDFImageShader : public SkPDFStream, public SkPDFShader {
572 public: 581 public:
573 explicit SkPDFImageShader(SkPDFShader::State* state); 582 explicit SkPDFImageShader(SkPDFShaderState* state);
574 virtual ~SkPDFImageShader() { 583 virtual ~SkPDFImageShader() {
575 if (isValid()) { 584 if (isValid()) {
576 RemoveShader(this); 585 SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
586 SkPDFCanon::GetCanon().removeShader(this);
577 } 587 }
578 fResources.unrefAll(); 588 fResources.unrefAll();
579 } 589 }
580 590
581 bool isValid() SK_OVERRIDE { return size() > 0; } 591 bool isValid() SK_OVERRIDE { return size() > 0; }
582 592
593 virtual SkPDFObject* toPDFObject() SK_OVERRIDE {
594 return this;
595 }
596
583 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 597 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
584 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE { 598 SkTSet<SkPDFObject*>* newResourceObjects) SK_OVERRIDE {
585 GetResourcesHelper(&fResources.toArray(), 599 GetResourcesHelper(&fResources.toArray(),
586 knownResourceObjects, 600 knownResourceObjects,
587 newResourceObjects); 601 newResourceObjects);
588 } 602 }
589 603
590 private: 604 private:
591 SkTSet<SkPDFObject*> fResources; 605 SkTSet<SkPDFObject*> fResources;
592 SkAutoTDelete<const SkPDFShader::State> fState;
593 }; 606 };
594 607
595 SkPDFShader::SkPDFShader() {} 608 SkPDFShader::SkPDFShader(const SkPDFShaderState* state)
609 : fPDFShaderState(state) {
610 }
611
612 SkPDFShader::~SkPDFShader() {
613 }
614
615 bool SkPDFShader::equals(const SkPDFShaderState& state) const {
616 return state == this->pdfShaderState();
617 }
618
619 const SkPDFShaderState& SkPDFShader::pdfShaderState() const {
620 return *fPDFShaderState;
621 }
596 622
597 // static 623 // static
598 SkPDFObject* SkPDFShader::GetPDFShaderByState(State* inState) { 624 SkPDFObject* SkPDFShader::GetPDFShaderByState(SkPDFShaderState* inState) {
599 SkPDFObject* result; 625 SkAutoTDelete<SkPDFShaderState> shaderState(inState);
600
601 SkAutoTDelete<State> shaderState(inState);
602 if (shaderState.get()->fType == SkShader::kNone_GradientType && 626 if (shaderState.get()->fType == SkShader::kNone_GradientType &&
603 shaderState.get()->fImage.isNull()) { 627 shaderState.get()->fImage.isNull()) {
604 // TODO(vandebo) This drops SKComposeShader on the floor. We could 628 // TODO(vandebo) This drops SKComposeShader on the floor. We could
605 // handle compose shader by pulling things up to a layer, drawing with 629 // handle compose shader by pulling things up to a layer, drawing with
606 // the first shader, applying the xfer mode and drawing again with the 630 // the first shader, applying the xfer mode and drawing again with the
607 // second shader, then applying the layer to the original drawing. 631 // second shader, then applying the layer to the original drawing.
608 return NULL; 632 return NULL;
609 } 633 }
610 634
611 ShaderCanonicalEntry entry(NULL, shaderState.get()); 635 SkPDFShader* pdfShader = SkPDFCanon::GetCanon().findShader(*shaderState);
612 int index = CanonicalShaders().find(entry); 636 if (pdfShader) {
613 if (index >= 0) { 637 return SkRef(pdfShader->toPDFObject());
614 result = CanonicalShaders()[index].fPDFShader;
615 result->ref();
616 return result;
617 } 638 }
618 639
619 bool valid = false;
620 // The PDFShader takes ownership of the shaderSate. 640 // The PDFShader takes ownership of the shaderSate.
621 if (shaderState.get()->fType == SkShader::kNone_GradientType) { 641 if (shaderState->fType == SkShader::kNone_GradientType) {
622 SkPDFImageShader* imageShader = 642 SkPDFImageShader* imageShader =
623 new SkPDFImageShader(shaderState.detach()); 643 new SkPDFImageShader(shaderState.detach());
624 valid = imageShader->isValid(); 644 if (imageShader->isValid()) {
mtklein 2015/01/20 21:59:52 Might want to extract this if-else block as add_to
hal.canary 2015/01/21 17:07:51 GREAT idea
625 result = imageShader; 645 SkPDFCanon::GetCanon().addShader(imageShader);
646 return imageShader->toPDFObject();
647 } else {
648 SkDELETE(imageShader);
649 return NULL;
650 }
651 } else if (shaderState->GradientHasAlpha()) {
652 SkPDFAlphaFunctionShader* gradientShader =
653 SkNEW_ARGS(SkPDFAlphaFunctionShader, (shaderState.detach()));
654 if (gradientShader->isValid()) {
655 SkPDFCanon::GetCanon().addShader(gradientShader);
656 return gradientShader->toPDFObject();
657 } else {
658 SkDELETE(gradientShader);
659 return NULL;
660 }
626 } else { 661 } else {
627 if (shaderState.get()->GradientHasAlpha()) { 662 SkPDFFunctionShader* functionShader =
628 SkPDFAlphaFunctionShader* gradientShader = 663 SkNEW_ARGS(SkPDFFunctionShader, (shaderState.detach()));
629 SkNEW_ARGS(SkPDFAlphaFunctionShader, (shaderState.detach())); 664 if (functionShader->isValid()) {
630 valid = gradientShader->isValid(); 665 SkPDFCanon::GetCanon().addShader(functionShader);
631 result = gradientShader; 666 return functionShader->toPDFObject();
632 } else { 667 } else {
633 SkPDFFunctionShader* functionShader = 668 SkDELETE(functionShader);
634 SkNEW_ARGS(SkPDFFunctionShader, (shaderState.detach())); 669 return NULL;
635 valid = functionShader->isValid();
636 result = functionShader;
637 } 670 }
638 } 671 }
639 if (!valid) {
640 delete result;
641 return NULL;
642 }
643 entry.fPDFShader = result;
644 CanonicalShaders().push(entry);
645 return result; // return the reference that came from new.
646 }
647
648 // static
649 void SkPDFShader::RemoveShader(SkPDFObject* shader) {
650 SkAutoMutexAcquire lock(CanonicalShadersMutex());
651 ShaderCanonicalEntry entry(shader, NULL);
652 int index = CanonicalShaders().find(entry);
653 SkASSERT(index >= 0);
654 CanonicalShaders().removeShuffle(index);
655 } 672 }
656 673
657 // static 674 // static
658 SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader, 675 SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader,
659 const SkMatrix& matrix, 676 const SkMatrix& matrix,
660 const SkIRect& surfaceBBox) { 677 const SkIRect& surfaceBBox) {
661 SkAutoMutexAcquire lock(CanonicalShadersMutex()); 678 SkAutoMutexAcquire lock(SkPDFCanon::GetShaderMutex());
662 return GetPDFShaderByState( 679 return GetPDFShaderByState(
663 SkNEW_ARGS(State, (shader, matrix, surfaceBBox))); 680 SkNEW_ARGS(SkPDFShaderState, (shader, matrix, surfaceBBox)));
664 }
665
666 // static
667 SkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() {
668 SkPDFShader::CanonicalShadersMutex().assertHeld();
669 static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders;
670 return gCanonicalShaders;
671 }
672
673 SK_DECLARE_STATIC_MUTEX(gCanonicalShadersMutex);
674 // static
675 SkBaseMutex& SkPDFShader::CanonicalShadersMutex() {
676 return gCanonicalShadersMutex;
677 } 681 }
678 682
679 // static 683 // static
680 SkPDFObject* SkPDFFunctionShader::RangeObject() { 684 SkPDFObject* SkPDFFunctionShader::RangeObject() {
681 SkPDFShader::CanonicalShadersMutex().assertHeld(); 685 SkPDFCanon::GetShaderMutex().assertHeld();
682 static SkPDFArray* range = NULL; 686 static SkPDFArray* range = NULL;
683 // This method is only used with CanonicalShadersMutex, so it's safe to 687 // This method is only used with CanonicalShadersMutex, so it's safe to
684 // populate domain. 688 // populate domain.
685 if (range == NULL) { 689 if (range == NULL) {
686 range = new SkPDFArray; 690 range = new SkPDFArray;
687 range->reserve(6); 691 range->reserve(6);
688 range->appendInt(0); 692 range->appendInt(0);
689 range->appendInt(1); 693 range->appendInt(1);
690 range->appendInt(0); 694 range->appendInt(0);
691 range->appendInt(1); 695 range->appendInt(1);
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 753
750 return content.detachAsStream(); 754 return content.detachAsStream();
751 } 755 }
752 756
753 /** 757 /**
754 * Creates a ExtGState with the SMask set to the luminosityShader in 758 * Creates a ExtGState with the SMask set to the luminosityShader in
755 * luminosity mode. The shader pattern extends to the bbox. 759 * luminosity mode. The shader pattern extends to the bbox.
756 */ 760 */
757 SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() { 761 SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState() {
758 SkRect bbox; 762 SkRect bbox;
759 bbox.set(fState.get()->fBBox); 763 bbox.set(this->pdfShaderState().fBBox);
760 764
761 SkAutoTUnref<SkPDFObject> luminosityShader( 765 SkAutoTUnref<SkPDFObject> luminosityShader(SkPDFShader::GetPDFShaderByState(
762 SkPDFShader::GetPDFShaderByState( 766 this->pdfShaderState().CreateAlphaToLuminosityState()));
763 fState->CreateAlphaToLuminosityState()));
764 767
765 SkAutoTUnref<SkStream> alphaStream(create_pattern_fill_content(-1, bbox)); 768 SkAutoTUnref<SkStream> alphaStream(create_pattern_fill_content(-1, bbox));
766 769
767 SkAutoTUnref<SkPDFResourceDict> 770 SkAutoTUnref<SkPDFResourceDict>
768 resources(get_gradient_resource_dict(luminosityShader, NULL)); 771 resources(get_gradient_resource_dict(luminosityShader, NULL));
769 772
770 SkAutoTUnref<SkPDFFormXObject> alphaMask( 773 SkAutoTUnref<SkPDFFormXObject> alphaMask(
771 new SkPDFFormXObject(alphaStream.get(), bbox, resources.get())); 774 new SkPDFFormXObject(alphaStream.get(), bbox, resources.get()));
772 775
773 return SkPDFGraphicState::GetSMaskGraphicState( 776 return SkPDFGraphicState::GetSMaskGraphicState(
774 alphaMask.get(), false, 777 alphaMask.get(), false,
775 SkPDFGraphicState::kLuminosity_SMaskMode); 778 SkPDFGraphicState::kLuminosity_SMaskMode);
776 } 779 }
777 780
778 SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state) 781 SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShaderState* state)
779 : fState(state) { 782 : SkPDFShader(state) {
780 SkRect bbox; 783 SkRect bbox;
781 bbox.set(fState.get()->fBBox); 784 bbox.set(this->pdfShaderState().fBBox);
782 785
783 fColorShader.reset( 786 fColorShader.reset(
784 SkPDFShader::GetPDFShaderByState(state->CreateOpaqueState())); 787 SkPDFShader::GetPDFShaderByState(state->CreateOpaqueState()));
785 788
786 // Create resource dict with alpha graphics state as G0 and 789 // Create resource dict with alpha graphics state as G0 and
787 // pattern shader as P0, then write content stream. 790 // pattern shader as P0, then write content stream.
788 SkAutoTUnref<SkPDFGraphicState> alphaGs(CreateSMaskGraphicState()); 791 SkAutoTUnref<SkPDFGraphicState> alphaGs(CreateSMaskGraphicState());
789 fResourceDict.reset( 792 fResourceDict.reset(
790 get_gradient_resource_dict(fColorShader.get(), alphaGs.get())); 793 get_gradient_resource_dict(fColorShader.get(), alphaGs.get()));
791 794
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
828 zero, one, zero, 831 zero, one, zero,
829 -p0/p2, -p1/p2, 1/p2); 832 -p0/p2, -p1/p2, 1/p2);
830 833
831 affine->setAll(sx - p0 * tx / p2, kx - p1 * tx / p2, tx / p2, 834 affine->setAll(sx - p0 * tx / p2, kx - p1 * tx / p2, tx / p2,
832 ky - p0 * ty / p2, sy - p1 * ty / p2, ty / p2, 835 ky - p0 * ty / p2, sy - p1 * ty / p2, ty / p2,
833 zero, zero, one); 836 zero, zero, one);
834 837
835 return true; 838 return true;
836 } 839 }
837 840
838 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) 841 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShaderState* state)
839 : SkPDFDict("Pattern"), 842 : SkPDFDict("Pattern"), SkPDFShader(state) {
840 fState(state) {
841 SkString (*codeFunction)(const SkShader::GradientInfo& info, 843 SkString (*codeFunction)(const SkShader::GradientInfo& info,
842 const SkMatrix& perspectiveRemover) = NULL; 844 const SkMatrix& perspectiveRemover) = NULL;
843 SkPoint transformPoints[2]; 845 SkPoint transformPoints[2];
844 846
845 // Depending on the type of the gradient, we want to transform the 847 // Depending on the type of the gradient, we want to transform the
846 // coordinate space in different ways. 848 // coordinate space in different ways.
847 const SkShader::GradientInfo* info = &fState.get()->fInfo; 849 const SkShader::GradientInfo* info = &this->pdfShaderState().fInfo;
mtklein 2015/01/20 21:59:52 Why don't we just write "this->pdfShaderState()" a
hal.canary 2015/01/21 17:07:51 Done.
848 transformPoints[0] = info->fPoint[0]; 850 transformPoints[0] = info->fPoint[0];
849 transformPoints[1] = info->fPoint[1]; 851 transformPoints[1] = info->fPoint[1];
850 switch (fState.get()->fType) { 852 switch (this->pdfShaderState().fType) {
851 case SkShader::kLinear_GradientType: 853 case SkShader::kLinear_GradientType:
852 codeFunction = &linearCode; 854 codeFunction = &linearCode;
853 break; 855 break;
854 case SkShader::kRadial_GradientType: 856 case SkShader::kRadial_GradientType:
855 transformPoints[1] = transformPoints[0]; 857 transformPoints[1] = transformPoints[0];
856 transformPoints[1].fX += info->fRadius[0]; 858 transformPoints[1].fX += info->fRadius[0];
857 codeFunction = &radialCode; 859 codeFunction = &radialCode;
858 break; 860 break;
859 case SkShader::kRadial2_GradientType: { 861 case SkShader::kRadial2_GradientType: {
860 // Bail out if the radii are the same. Empty fResources signals 862 // Bail out if the radii are the same. Empty fResources signals
(...skipping 24 matching lines...) Expand all
885 return; 887 return;
886 } 888 }
887 889
888 // Move any scaling (assuming a unit gradient) or translation 890 // Move any scaling (assuming a unit gradient) or translation
889 // (and rotation for linear gradient), of the final gradient from 891 // (and rotation for linear gradient), of the final gradient from
890 // info->fPoints to the matrix (updating bbox appropriately). Now 892 // info->fPoints to the matrix (updating bbox appropriately). Now
891 // the gradient can be drawn on on the unit segment. 893 // the gradient can be drawn on on the unit segment.
892 SkMatrix mapperMatrix; 894 SkMatrix mapperMatrix;
893 unitToPointsMatrix(transformPoints, &mapperMatrix); 895 unitToPointsMatrix(transformPoints, &mapperMatrix);
894 896
895 SkMatrix finalMatrix = fState.get()->fCanvasTransform; 897 SkMatrix finalMatrix = this->pdfShaderState().fCanvasTransform;
896 finalMatrix.preConcat(fState.get()->fShaderTransform); 898 finalMatrix.preConcat(this->pdfShaderState().fShaderTransform);
897 finalMatrix.preConcat(mapperMatrix); 899 finalMatrix.preConcat(mapperMatrix);
898 900
899 // Preserves as much as posible in the final matrix, and only removes 901 // Preserves as much as posible in the final matrix, and only removes
900 // the perspective. The inverse of the perspective is stored in 902 // the perspective. The inverse of the perspective is stored in
901 // perspectiveInverseOnly matrix and has 3 useful numbers 903 // perspectiveInverseOnly matrix and has 3 useful numbers
902 // (p0, p1, p2), while everything else is either 0 or 1. 904 // (p0, p1, p2), while everything else is either 0 or 1.
903 // In this way the shader will handle it eficiently, with minimal code. 905 // In this way the shader will handle it eficiently, with minimal code.
904 SkMatrix perspectiveInverseOnly = SkMatrix::I(); 906 SkMatrix perspectiveInverseOnly = SkMatrix::I();
905 if (finalMatrix.hasPerspective()) { 907 if (finalMatrix.hasPerspective()) {
906 if (!split_perspective(finalMatrix, 908 if (!split_perspective(finalMatrix,
907 &finalMatrix, &perspectiveInverseOnly)) { 909 &finalMatrix, &perspectiveInverseOnly)) {
908 return; 910 return;
909 } 911 }
910 } 912 }
911 913
912 SkRect bbox; 914 SkRect bbox;
913 bbox.set(fState.get()->fBBox); 915 bbox.set(this->pdfShaderState().fBBox);
914 if (!inverseTransformBBox(finalMatrix, &bbox)) { 916 if (!inverseTransformBBox(finalMatrix, &bbox)) {
915 return; 917 return;
916 } 918 }
917 919
918 SkAutoTUnref<SkPDFArray> domain(new SkPDFArray); 920 SkAutoTUnref<SkPDFArray> domain(new SkPDFArray);
919 domain->reserve(4); 921 domain->reserve(4);
920 domain->appendScalar(bbox.fLeft); 922 domain->appendScalar(bbox.fLeft);
921 domain->appendScalar(bbox.fRight); 923 domain->appendScalar(bbox.fRight);
922 domain->appendScalar(bbox.fTop); 924 domain->appendScalar(bbox.fTop);
923 domain->appendScalar(bbox.fBottom); 925 domain->appendScalar(bbox.fBottom);
924 926
925 SkString functionCode; 927 SkString functionCode;
926 // The two point radial gradient further references fState.get()->fInfo 928 // The two point radial gradient further references
929 // this->pdfShaderState().fInfo
927 // in translating from x, y coordinates to the t parameter. So, we have 930 // in translating from x, y coordinates to the t parameter. So, we have
928 // to transform the points and radii according to the calculated matrix. 931 // to transform the points and radii according to the calculated matrix.
929 if (fState.get()->fType == SkShader::kRadial2_GradientType) { 932 if (this->pdfShaderState().fType == SkShader::kRadial2_GradientType) {
930 SkShader::GradientInfo twoPointRadialInfo = *info; 933 SkShader::GradientInfo twoPointRadialInfo = *info;
931 SkMatrix inverseMapperMatrix; 934 SkMatrix inverseMapperMatrix;
932 if (!mapperMatrix.invert(&inverseMapperMatrix)) { 935 if (!mapperMatrix.invert(&inverseMapperMatrix)) {
933 return; 936 return;
934 } 937 }
935 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); 938 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2);
936 twoPointRadialInfo.fRadius[0] = 939 twoPointRadialInfo.fRadius[0] =
937 inverseMapperMatrix.mapRadius(info->fRadius[0]); 940 inverseMapperMatrix.mapRadius(info->fRadius[0]);
938 twoPointRadialInfo.fRadius[1] = 941 twoPointRadialInfo.fRadius[1] =
939 inverseMapperMatrix.mapRadius(info->fRadius[1]); 942 inverseMapperMatrix.mapRadius(info->fRadius[1]);
940 functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly); 943 functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly);
941 } else { 944 } else {
942 functionCode = codeFunction(*info, perspectiveInverseOnly); 945 functionCode = codeFunction(*info, perspectiveInverseOnly);
943 } 946 }
944 947
945 SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict); 948 SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict);
946 pdfShader->insertInt("ShadingType", 1); 949 pdfShader->insertInt("ShadingType", 1);
947 pdfShader->insertName("ColorSpace", "DeviceRGB"); 950 pdfShader->insertName("ColorSpace", "DeviceRGB");
948 pdfShader->insert("Domain", domain.get()); 951 pdfShader->insert("Domain", domain.get());
949 952
950 SkPDFStream* function = makePSFunction(functionCode, domain.get()); 953 SkPDFStream* function = makePSFunction(functionCode, domain.get());
951 pdfShader->insert("Function", new SkPDFObjRef(function))->unref(); 954 pdfShader->insert("Function", new SkPDFObjRef(function))->unref();
952 fResources.push(function); // Pass ownership to resource list. 955 fResources.push(function); // Pass ownership to resource list.
953 956
954 insertInt("PatternType", 2); 957 insertInt("PatternType", 2);
955 insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref(); 958 insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
956 insert("Shading", pdfShader.get()); 959 insert("Shading", pdfShader.get());
957 } 960 }
958 961
959 SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) { 962 SkPDFImageShader::SkPDFImageShader(SkPDFShaderState* state)
960 fState.get()->fImage.lockPixels(); 963 : SkPDFShader(state) {
964 this->pdfShaderState().fImage.lockPixels();
961 965
962 // The image shader pattern cell will be drawn into a separate device 966 // The image shader pattern cell will be drawn into a separate device
963 // in pattern cell space (no scaling on the bitmap, though there may be 967 // in pattern cell space (no scaling on the bitmap, though there may be
964 // translations so that all content is in the device, coordinates > 0). 968 // translations so that all content is in the device, coordinates > 0).
965 969
966 // Map clip bounds to shader space to ensure the device is large enough 970 // Map clip bounds to shader space to ensure the device is large enough
967 // to handle fake clamping. 971 // to handle fake clamping.
968 SkMatrix finalMatrix = fState.get()->fCanvasTransform; 972 SkMatrix finalMatrix = this->pdfShaderState().fCanvasTransform;
969 finalMatrix.preConcat(fState.get()->fShaderTransform); 973 finalMatrix.preConcat(this->pdfShaderState().fShaderTransform);
970 SkRect deviceBounds; 974 SkRect deviceBounds;
971 deviceBounds.set(fState.get()->fBBox); 975 deviceBounds.set(this->pdfShaderState().fBBox);
972 if (!inverseTransformBBox(finalMatrix, &deviceBounds)) { 976 if (!inverseTransformBBox(finalMatrix, &deviceBounds)) {
973 return; 977 return;
974 } 978 }
975 979
976 const SkBitmap* image = &fState.get()->fImage; 980 const SkBitmap* image = &this->pdfShaderState().fImage;
977 SkRect bitmapBounds; 981 SkRect bitmapBounds;
978 image->getBounds(&bitmapBounds); 982 image->getBounds(&bitmapBounds);
979 983
980 // For tiling modes, the bounds should be extended to include the bitmap, 984 // For tiling modes, the bounds should be extended to include the bitmap,
981 // otherwise the bitmap gets clipped out and the shader is empty and awful. 985 // otherwise the bitmap gets clipped out and the shader is empty and awful.
982 // For clamp modes, we're only interested in the clip region, whether 986 // For clamp modes, we're only interested in the clip region, whether
983 // or not the main bitmap is in it. 987 // or not the main bitmap is in it.
984 SkShader::TileMode tileModes[2]; 988 SkShader::TileMode tileModes[2];
985 tileModes[0] = fState.get()->fImageTileModes[0]; 989 tileModes[0] = this->pdfShaderState().fImageTileModes[0];
986 tileModes[1] = fState.get()->fImageTileModes[1]; 990 tileModes[1] = this->pdfShaderState().fImageTileModes[1];
987 if (tileModes[0] != SkShader::kClamp_TileMode || 991 if (tileModes[0] != SkShader::kClamp_TileMode ||
988 tileModes[1] != SkShader::kClamp_TileMode) { 992 tileModes[1] != SkShader::kClamp_TileMode) {
989 deviceBounds.join(bitmapBounds); 993 deviceBounds.join(bitmapBounds);
990 } 994 }
991 995
992 SkMatrix unflip; 996 SkMatrix unflip;
993 unflip.setTranslate(0, SkScalarRoundToScalar(deviceBounds.height())); 997 unflip.setTranslate(0, SkScalarRoundToScalar(deviceBounds.height()));
994 unflip.preScale(SK_Scalar1, -SK_Scalar1); 998 unflip.preScale(SK_Scalar1, -SK_Scalar1);
995 SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()), 999 SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()),
996 SkScalarRoundToInt(deviceBounds.height())); 1000 SkScalarRoundToInt(deviceBounds.height()));
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
1156 1160
1157 // Put the canvas into the pattern stream (fContent). 1161 // Put the canvas into the pattern stream (fContent).
1158 SkAutoTUnref<SkStream> content(pattern.content()); 1162 SkAutoTUnref<SkStream> content(pattern.content());
1159 setData(content.get()); 1163 setData(content.get());
1160 SkPDFResourceDict* resourceDict = pattern.getResourceDict(); 1164 SkPDFResourceDict* resourceDict = pattern.getResourceDict();
1161 resourceDict->getReferencedResources(fResources, &fResources, false); 1165 resourceDict->getReferencedResources(fResources, &fResources, false);
1162 1166
1163 populate_tiling_pattern_dict(this, patternBBox, 1167 populate_tiling_pattern_dict(this, patternBBox,
1164 pattern.getResourceDict(), finalMatrix); 1168 pattern.getResourceDict(), finalMatrix);
1165 1169
1166 fState.get()->fImage.unlockPixels(); 1170 this->pdfShaderState().fImage.unlockPixels();
1167 } 1171 }
1168 1172
1169 SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, SkPDFAr ray* domain) { 1173 SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, SkPDFAr ray* domain) {
1170 SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(), psCode.size())) ; 1174 SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(), psCode.size())) ;
1171 SkPDFStream* result = new SkPDFStream(funcData.get()); 1175 SkPDFStream* result = new SkPDFStream(funcData.get());
1172 result->insertInt("FunctionType", 4); 1176 result->insertInt("FunctionType", 4);
1173 result->insert("Domain", domain); 1177 result->insert("Domain", domain);
1174 result->insert("Range", RangeObject()); 1178 result->insert("Range", RangeObject());
1175 return result; 1179 return result;
1176 } 1180 }
1177 1181
1178 SkPDFShader::ShaderCanonicalEntry::ShaderCanonicalEntry(SkPDFObject* pdfShader, const State* state) 1182 bool SkPDFShaderState::operator==(const SkPDFShaderState& b) const {
1179 : fPDFShader(pdfShader)
1180 , fState(state)
1181 {}
1182
1183 bool SkPDFShader::ShaderCanonicalEntry::operator==(const ShaderCanonicalEntry& b ) const {
1184 return fPDFShader == b.fPDFShader ||
1185 (fState != NULL && b.fState != NULL && *fState == *b.fState);
1186 }
1187
1188 bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const {
1189 if (fType != b.fType || 1183 if (fType != b.fType ||
1190 fCanvasTransform != b.fCanvasTransform || 1184 fCanvasTransform != b.fCanvasTransform ||
1191 fShaderTransform != b.fShaderTransform || 1185 fShaderTransform != b.fShaderTransform ||
1192 fBBox != b.fBBox) { 1186 fBBox != b.fBBox) {
1193 return false; 1187 return false;
1194 } 1188 }
1195 1189
1196 if (fType == SkShader::kNone_GradientType) { 1190 if (fType == SkShader::kNone_GradientType) {
1197 if (fPixelGeneration != b.fPixelGeneration || 1191 if (fPixelGeneration != b.fPixelGeneration ||
1198 fPixelGeneration == 0 || 1192 fPixelGeneration == 0 ||
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1232 break; 1226 break;
1233 case SkShader::kSweep_GradientType: 1227 case SkShader::kSweep_GradientType:
1234 case SkShader::kNone_GradientType: 1228 case SkShader::kNone_GradientType:
1235 case SkShader::kColor_GradientType: 1229 case SkShader::kColor_GradientType:
1236 break; 1230 break;
1237 } 1231 }
1238 } 1232 }
1239 return true; 1233 return true;
1240 } 1234 }
1241 1235
1242 SkPDFShader::State::State(const SkShader& shader, 1236 SkPDFShaderState::SkPDFShaderState(const SkShader& shader,
1243 const SkMatrix& canvasTransform, const SkIRect& bbox) 1237 const SkMatrix& canvasTransform,
1244 : fCanvasTransform(canvasTransform), 1238 const SkIRect& bbox)
1245 fBBox(bbox), 1239 : fCanvasTransform(canvasTransform), fBBox(bbox), fPixelGeneration(0) {
1246 fPixelGeneration(0) {
1247 fInfo.fColorCount = 0; 1240 fInfo.fColorCount = 0;
1248 fInfo.fColors = NULL; 1241 fInfo.fColors = NULL;
1249 fInfo.fColorOffsets = NULL; 1242 fInfo.fColorOffsets = NULL;
1250 fShaderTransform = shader.getLocalMatrix(); 1243 fShaderTransform = shader.getLocalMatrix();
1251 fImageTileModes[0] = fImageTileModes[1] = SkShader::kClamp_TileMode; 1244 fImageTileModes[0] = fImageTileModes[1] = SkShader::kClamp_TileMode;
1252 1245
1253 fType = shader.asAGradient(&fInfo); 1246 fType = shader.asAGradient(&fInfo);
1254 1247
1255 if (fType == SkShader::kNone_GradientType) { 1248 if (fType == SkShader::kNone_GradientType) {
1256 SkShader::BitmapType bitmapType; 1249 SkShader::BitmapType bitmapType;
1257 SkMatrix matrix; 1250 SkMatrix matrix;
1258 bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes); 1251 bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes);
1259 if (bitmapType != SkShader::kDefault_BitmapType) { 1252 if (bitmapType != SkShader::kDefault_BitmapType) {
1260 fImage.reset(); 1253 fImage.reset();
1261 return; 1254 return;
1262 } 1255 }
1263 SkASSERT(matrix.isIdentity()); 1256 SkASSERT(matrix.isIdentity());
1264 fPixelGeneration = fImage.getGenerationID(); 1257 fPixelGeneration = fImage.getGenerationID();
1265 } else { 1258 } else {
1266 AllocateGradientInfoStorage(); 1259 AllocateGradientInfoStorage();
1267 shader.asAGradient(&fInfo); 1260 shader.asAGradient(&fInfo);
1268 } 1261 }
1269 } 1262 }
1270 1263
1271 SkPDFShader::State::State(const SkPDFShader::State& other) 1264 SkPDFShaderState::SkPDFShaderState(const SkPDFShaderState& other)
1272 : fType(other.fType), 1265 : fType(other.fType)
1273 fCanvasTransform(other.fCanvasTransform), 1266 , fCanvasTransform(other.fCanvasTransform)
1274 fShaderTransform(other.fShaderTransform), 1267 , fShaderTransform(other.fShaderTransform)
1275 fBBox(other.fBBox) 1268 , fBBox(other.fBBox) {
1276 {
1277 // Only gradients supported for now, since that is all that is used. 1269 // Only gradients supported for now, since that is all that is used.
1278 // If needed, image state copy constructor can be added here later. 1270 // If needed, image state copy constructor can be added here later.
1279 SkASSERT(fType != SkShader::kNone_GradientType); 1271 SkASSERT(fType != SkShader::kNone_GradientType);
1280 1272
1281 if (fType != SkShader::kNone_GradientType) { 1273 if (fType != SkShader::kNone_GradientType) {
1282 fInfo = other.fInfo; 1274 fInfo = other.fInfo;
1283 1275
1284 AllocateGradientInfoStorage(); 1276 AllocateGradientInfoStorage();
1285 for (int i = 0; i < fInfo.fColorCount; i++) { 1277 for (int i = 0; i < fInfo.fColorCount; i++) {
1286 fInfo.fColors[i] = other.fInfo.fColors[i]; 1278 fInfo.fColors[i] = other.fInfo.fColors[i];
1287 fInfo.fColorOffsets[i] = other.fInfo.fColorOffsets[i]; 1279 fInfo.fColorOffsets[i] = other.fInfo.fColorOffsets[i];
1288 } 1280 }
1289 } 1281 }
1290 } 1282 }
1291 1283
1292 /** 1284 /**
1293 * Create a copy of this gradient state with alpha assigned to RGB luminousity. 1285 * Create a copy of this gradient state with alpha assigned to RGB luminousity.
1294 * Only valid for gradient states. 1286 * Only valid for gradient states.
1295 */ 1287 */
1296 SkPDFShader::State* SkPDFShader::State::CreateAlphaToLuminosityState() const { 1288 SkPDFShaderState* SkPDFShaderState::CreateAlphaToLuminosityState() const {
1297 SkASSERT(fType != SkShader::kNone_GradientType); 1289 SkASSERT(fType != SkShader::kNone_GradientType);
1298 1290
1299 SkPDFShader::State* newState = new SkPDFShader::State(*this); 1291 SkPDFShaderState* newState = new SkPDFShaderState(*this);
1300 1292
1301 for (int i = 0; i < fInfo.fColorCount; i++) { 1293 for (int i = 0; i < fInfo.fColorCount; i++) {
1302 SkAlpha alpha = SkColorGetA(fInfo.fColors[i]); 1294 SkAlpha alpha = SkColorGetA(fInfo.fColors[i]);
1303 newState->fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha); 1295 newState->fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha);
1304 } 1296 }
1305 1297
1306 return newState; 1298 return newState;
1307 } 1299 }
1308 1300
1309 /** 1301 /**
1310 * Create a copy of this gradient state with alpha set to fully opaque 1302 * Create a copy of this gradient state with alpha set to fully opaque
1311 * Only valid for gradient states. 1303 * Only valid for gradient states.
1312 */ 1304 */
1313 SkPDFShader::State* SkPDFShader::State::CreateOpaqueState() const { 1305 SkPDFShaderState* SkPDFShaderState::CreateOpaqueState() const {
1314 SkASSERT(fType != SkShader::kNone_GradientType); 1306 SkASSERT(fType != SkShader::kNone_GradientType);
1315 1307
1316 SkPDFShader::State* newState = new SkPDFShader::State(*this); 1308 SkPDFShaderState* newState = new SkPDFShaderState(*this);
1317 for (int i = 0; i < fInfo.fColorCount; i++) { 1309 for (int i = 0; i < fInfo.fColorCount; i++) {
1318 newState->fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i], 1310 newState->fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i],
1319 SK_AlphaOPAQUE); 1311 SK_AlphaOPAQUE);
1320 } 1312 }
1321 1313
1322 return newState; 1314 return newState;
1323 } 1315 }
1324 1316
1325 /** 1317 /**
1326 * Returns true if state is a gradient and the gradient has alpha. 1318 * Returns true if state is a gradient and the gradient has alpha.
1327 */ 1319 */
1328 bool SkPDFShader::State::GradientHasAlpha() const { 1320 bool SkPDFShaderState::GradientHasAlpha() const {
1329 if (fType == SkShader::kNone_GradientType) { 1321 if (fType == SkShader::kNone_GradientType) {
1330 return false; 1322 return false;
1331 } 1323 }
1332 1324
1333 for (int i = 0; i < fInfo.fColorCount; i++) { 1325 for (int i = 0; i < fInfo.fColorCount; i++) {
1334 SkAlpha alpha = SkColorGetA(fInfo.fColors[i]); 1326 SkAlpha alpha = SkColorGetA(fInfo.fColors[i]);
1335 if (alpha != SK_AlphaOPAQUE) { 1327 if (alpha != SK_AlphaOPAQUE) {
1336 return true; 1328 return true;
1337 } 1329 }
1338 } 1330 }
1339 return false; 1331 return false;
1340 } 1332 }
1341 1333
1342 void SkPDFShader::State::AllocateGradientInfoStorage() { 1334 void SkPDFShaderState::AllocateGradientInfoStorage() {
1343 fColorData.set(sk_malloc_throw( 1335 fColorData.set(sk_malloc_throw(
1344 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); 1336 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar))));
1345 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); 1337 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get());
1346 fInfo.fColorOffsets = 1338 fInfo.fColorOffsets =
1347 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); 1339 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount);
1348 } 1340 }
OLDNEW
« src/pdf/SkPDFShader.h ('K') | « src/pdf/SkPDFShader.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698