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

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

Issue 18585002: Implemented transparent gradients (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: More code review fixes. Created 7 years, 5 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 | Annotate | Revision Log
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 "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
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);
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
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 SkPDFGraphicState* CreateSMaskGraphicState(
480 SkPDFShader::State* luminosityState, SkRect& bbox);
481
482 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
483 SkTSet<SkPDFObject*>* newResourceObjects) {
484 fResourceDict->getResources(knownResourceObjects,
485 newResourceObjects,
486 true);
487 }
488
489 SkAutoTUnref<SkPDFObject> fColorPattern;
490 SkAutoTUnref<SkPDFResourceDict> fResourceDict;
491 };
492
444 class SkPDFImageShader : public SkPDFStream, public SkPDFShader { 493 class SkPDFImageShader : public SkPDFStream, public SkPDFShader {
445 public: 494 public:
446 explicit SkPDFImageShader(SkPDFShader::State* state); 495 explicit SkPDFImageShader(SkPDFShader::State* state);
447 virtual ~SkPDFImageShader() { 496 virtual ~SkPDFImageShader() {
448 RemoveShader(this); 497 RemoveShader(this);
449 fResources.unrefAll(); 498 fResources.unrefAll();
450 } 499 }
451 500
452 virtual bool isValid() { return size() > 0; } 501 virtual bool isValid() { return size() > 0; }
453 502
454 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects, 503 void getResources(const SkTSet<SkPDFObject*>& knownResourceObjects,
455 SkTSet<SkPDFObject*>* newResourceObjects) { 504 SkTSet<SkPDFObject*>* newResourceObjects) {
456 GetResourcesHelper(&fResources.toArray(), 505 GetResourcesHelper(&fResources.toArray(),
457 knownResourceObjects, 506 knownResourceObjects,
458 newResourceObjects); 507 newResourceObjects);
459 } 508 }
460 509
461 private: 510 private:
462 SkTSet<SkPDFObject*> fResources; 511 SkTSet<SkPDFObject*> fResources;
463 SkAutoTDelete<const SkPDFShader::State> fState; 512 SkAutoTDelete<const SkPDFShader::State> fState;
464 }; 513 };
465 514
466 SkPDFShader::SkPDFShader() {} 515 SkPDFShader::SkPDFShader() {}
467 516
468 // static 517 // static
469 void SkPDFShader::RemoveShader(SkPDFObject* shader) { 518 // This is an internal method.
470 SkAutoMutexAcquire lock(CanonicalShadersMutex()); 519 // CanonicalShadersMutex() should already be acquired.
471 ShaderCanonicalEntry entry(shader, NULL); 520 SkPDFObject* SkPDFShader::GetPDFShaderByState(State* inState) {
472 int index = CanonicalShaders().find(entry); 521 SkPDFObject* result;
473 SkASSERT(index >= 0);
474 CanonicalShaders().removeShuffle(index);
475 }
476 522
477 // static 523 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 && 524 if (shaderState.get()->fType == SkShader::kNone_GradientType &&
485 shaderState.get()->fImage.isNull()) { 525 shaderState.get()->fImage.isNull()) {
486 // TODO(vandebo) This drops SKComposeShader on the floor. We could 526 // TODO(vandebo) This drops SKComposeShader on the floor. We could
487 // handle compose shader by pulling things up to a layer, drawing with 527 // 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 528 // the first shader, applying the xfer mode and drawing again with the
489 // second shader, then applying the layer to the original drawing. 529 // second shader, then applying the layer to the original drawing.
490 return NULL; 530 return NULL;
491 } 531 }
492 532
493 ShaderCanonicalEntry entry(NULL, shaderState.get()); 533 ShaderCanonicalEntry entry(NULL, shaderState.get());
494 int index = CanonicalShaders().find(entry); 534 int index = CanonicalShaders().find(entry);
495 if (index >= 0) { 535 if (index >= 0) {
496 result = CanonicalShaders()[index].fPDFShader; 536 result = CanonicalShaders()[index].fPDFShader;
497 result->ref(); 537 result->ref();
498 return result; 538 return result;
499 } 539 }
500 540
501 bool valid = false; 541 bool valid = false;
502 // The PDFShader takes ownership of the shaderSate. 542 // The PDFShader takes ownership of the shaderSate.
503 if (shaderState.get()->fType == SkShader::kNone_GradientType) { 543 if (shaderState.get()->fType == SkShader::kNone_GradientType) {
504 SkPDFImageShader* imageShader = 544 SkPDFImageShader* imageShader =
505 new SkPDFImageShader(shaderState.detach()); 545 new SkPDFImageShader(shaderState.detach());
506 valid = imageShader->isValid(); 546 valid = imageShader->isValid();
507 result = imageShader; 547 result = imageShader;
508 } else { 548 } else {
509 SkPDFFunctionShader* functionShader = 549 if (shaderState.get()->GradientHasAlpha()) {
510 new SkPDFFunctionShader(shaderState.detach()); 550 SkPDFAlphaFunctionShader* gradientShader =
511 valid = functionShader->isValid(); 551 new SkPDFAlphaFunctionShader(shaderState.detach());
512 result = functionShader; 552 valid = gradientShader->isValid();
553 result = gradientShader;
554 } else {
555 SkPDFFunctionShader* functionShader =
556 new SkPDFFunctionShader(shaderState.detach());
557 valid = functionShader->isValid();
558 result = functionShader;
559 }
513 } 560 }
514 if (!valid) { 561 if (!valid) {
515 delete result; 562 delete result;
516 return NULL; 563 return NULL;
517 } 564 }
518 entry.fPDFShader = result; 565 entry.fPDFShader = result;
519 CanonicalShaders().push(entry); 566 CanonicalShaders().push(entry);
520 return result; // return the reference that came from new. 567 return result; // return the reference that came from new.
521 } 568 }
522 569
523 // static 570 // static
571 void SkPDFShader::RemoveShader(SkPDFObject* shader) {
572 SkAutoMutexAcquire lock(CanonicalShadersMutex());
573 ShaderCanonicalEntry entry(shader, NULL);
574 int index = CanonicalShaders().find(entry);
575 SkASSERT(index >= 0);
576 CanonicalShaders().removeShuffle(index);
577 }
578
579 // static
580 SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader,
581 const SkMatrix& matrix,
582 const SkIRect& surfaceBBox) {
583 SkAutoMutexAcquire lock(CanonicalShadersMutex());
584 return GetPDFShaderByState(new State(shader, matrix, surfaceBBox));
585 }
586
587 // static
524 SkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() { 588 SkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() {
525 // This initialization is only thread safe with gcc. 589 // This initialization is only thread safe with gcc.
526 static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders; 590 static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders;
527 return gCanonicalShaders; 591 return gCanonicalShaders;
528 } 592 }
529 593
530 // static 594 // static
531 SkBaseMutex& SkPDFShader::CanonicalShadersMutex() { 595 SkBaseMutex& SkPDFShader::CanonicalShadersMutex() {
532 // This initialization is only thread safe with gcc or when 596 // This initialization is only thread safe with gcc or when
533 // POD-style mutex initialization is used. 597 // POD-style mutex initialization is used.
(...skipping 13 matching lines...) Expand all
547 range->appendInt(0); 611 range->appendInt(0);
548 range->appendInt(1); 612 range->appendInt(1);
549 range->appendInt(0); 613 range->appendInt(0);
550 range->appendInt(1); 614 range->appendInt(1);
551 range->appendInt(0); 615 range->appendInt(0);
552 range->appendInt(1); 616 range->appendInt(1);
553 } 617 }
554 return range; 618 return range;
555 } 619 }
556 620
621 static SkPDFResourceDict* get_gradient_resource_dict(
622 SkPDFObject* functionShader,
623 SkPDFObject* gState) {
624 SkPDFResourceDict* dict = new SkPDFResourceDict(true);
625
626 if (functionShader != NULL) {
627 dict->insertResourceAsRef(SkPDFResourceDict::kPattern_ResourceType, 0,
628 functionShader);
629 }
630 if (gState != NULL) {
631 dict->insertResourceAsRef(SkPDFResourceDict::kExtGState_ResourceType, 0,
632 gState);
633 }
634
635 return dict;
636 }
637
638 static void populate_tiling_pattern_dict(SkPDFDict* pattern,
639 SkRect& bbox, SkPDFDict* resources,
640 const SkMatrix& matrix) {
641 pattern->insertName("Type", "Pattern");
642 pattern->insertInt("PatternType", 1);
643 pattern->insertInt("PaintType", 1);
644 pattern->insertInt("TilingType", 1);
645 pattern->insert("BBox", SkPDFUtils::RectToArray(bbox))->unref();
646 pattern->insertScalar("XStep", bbox.width());
647 pattern->insertScalar("YStep", bbox.height());
648 pattern->insert("Resources", resources);
649 if (!matrix.isIdentity()) {
650 pattern->insert("Matrix", SkPDFUtils::MatrixToArray(matrix))->unref();
651 }
652 }
653
654 /**
655 * Creates a content stream which fills the pattern P0 across bounds.
656 * The argument setup may contain any relevant PDF content stream operators
657 * and will be prepended to the output content stream.
658 */
659 static SkData* create_pattern_fill_content(const char setup[], SkRect& bounds) {
660 SkDynamicMemoryWStream content;
661 if (NULL != setup) {
662 content.writeText(setup);
663 }
664 content.writeText("/Pattern CS/Pattern cs/P0 SCN/P0 scn\n");
665
666 SkPDFUtils::AppendRectangle(bounds, &content);
667 SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPath::kEvenOdd_FillType,
668 &content);
669
670 return content.copyToData();
671 }
672
673 /**
674 * Creates a ExtGState with the SMask set to the luminosityShader in
675 * luminosity mode. The shader pattern extends to the bbox.
676 */
677 SkPDFGraphicState* SkPDFAlphaFunctionShader::CreateSMaskGraphicState(
vandebo (ex-Chrome) 2013/07/12 21:41:44 Instead of passing in state, use fState. Instead o
ducky 2013/07/12 23:32:34 Done.
678 SkPDFShader::State* alphaState, SkRect& bbox) {
679 SkAutoTUnref<SkPDFObject> luminosityShader(SkPDFShader::GetPDFShaderByState(
vandebo (ex-Chrome) 2013/07/12 21:41:44 This might be easier to read as: SkAutoTUnref<
ducky 2013/07/12 23:32:34 Done. Using first since there are issues with the
680 alphaState->CreateAlphaToLuminosityState()));
681
682 SkAutoTUnref<SkData> alphaStream(create_pattern_fill_content(NULL, bbox));
683
684 SkAutoTUnref<SkPDFResourceDict>
685 resources(get_gradient_resource_dict(luminosityShader, NULL));
686
687 SkAutoTUnref<SkPDFFormXObject> alphaMask(
688 new SkPDFFormXObject(alphaStream.get(), bbox, resources.get()));
689
690 return SkPDFGraphicState::GetSMaskGraphicState(
691 alphaMask.get(), false,
692 SkPDFGraphicState::kLuminosity_SMaskMode);
693 }
694
695 SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state) :
696 fState(state) {
vandebo (ex-Chrome) 2013/07/12 21:41:44 nit: : fState(state) {
ducky 2013/07/12 23:32:34 Done.
697 SkRect bbox;
698 bbox.set(fState.get()->fBBox);
699
700 fColorPattern.reset(
vandebo (ex-Chrome) 2013/07/12 21:41:44 nit: Maybe fColorShader would be a better name, no
ducky 2013/07/12 23:32:34 Done.
701 SkPDFShader::GetPDFShaderByState(state->CreateOpaqueState()));
702
703 SkAutoTUnref<SkPDFGraphicState> alphaGs(
704 CreateSMaskGraphicState(state, bbox));
705
706 fResourceDict.reset(
707 get_gradient_resource_dict(fColorPattern.get(), alphaGs.get()));
708
709 SkAutoTUnref<SkData> colorStream(
710 create_pattern_fill_content("/G0 gs", bbox));
vandebo (ex-Chrome) 2013/07/12 21:41:44 you'll need to rebase this on the recent resource
ducky 2013/07/12 23:32:34 Done.
711 setData(colorStream.get());
712
713 populate_tiling_pattern_dict(this, bbox, fResourceDict.get(),
714 SkMatrix::I());
715 }
716
557 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state) 717 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
558 : SkPDFDict("Pattern"), 718 : SkPDFDict("Pattern"),
559 fState(state) { 719 fState(state) {
560 SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL; 720 SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL;
561 SkPoint transformPoints[2]; 721 SkPoint transformPoints[2];
562 722
563 // Depending on the type of the gradient, we want to transform the 723 // Depending on the type of the gradient, we want to transform the
564 // coordinate space in different ways. 724 // coordinate space in different ways.
565 const SkShader::GradientInfo* info = &fState.get()->fInfo; 725 const SkShader::GradientInfo* info = &fState.get()->fInfo;
566 transformPoints[0] = info->fPoint[0]; 726 transformPoints[0] = info->fPoint[0];
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
822 982
823 if (tileModes[0] == SkShader::kMirror_TileMode) { 983 if (tileModes[0] == SkShader::kMirror_TileMode) {
824 bottomMatrix.postScale(-1, 1); 984 bottomMatrix.postScale(-1, 1);
825 bottomMatrix.postTranslate(2 * width, 0); 985 bottomMatrix.postTranslate(2 * width, 0);
826 canvas.drawBitmapMatrix(bottom, bottomMatrix); 986 canvas.drawBitmapMatrix(bottom, bottomMatrix);
827 } 987 }
828 patternBBox.fBottom = surfaceBBox.height(); 988 patternBBox.fBottom = surfaceBBox.height();
829 } 989 }
830 } 990 }
831 991
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). 992 // Put the canvas into the pattern stream (fContent).
840 SkAutoTUnref<SkData> content(pattern.copyContentToData()); 993 SkAutoTUnref<SkData> content(pattern.copyContentToData());
841 setData(content.get()); 994 setData(content.get());
842 SkPDFResourceDict* resourceDict = pattern.getResourceDict(); 995 SkPDFResourceDict* resourceDict = pattern.getResourceDict();
843 resourceDict->getResources(fResources, &fResources, false); 996 resourceDict->getResources(fResources, &fResources, false);
844 997
845 insertName("Type", "Pattern"); 998 populate_tiling_pattern_dict(this, patternBBox,
846 insertInt("PatternType", 1); 999 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 1000
855 fState.get()->fImage.unlockPixels(); 1001 fState.get()->fImage.unlockPixels();
856 } 1002 }
857 1003
858 SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode, 1004 SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode,
859 SkPDFArray* domain) { 1005 SkPDFArray* domain) {
860 SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(), 1006 SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(),
861 psCode.size())); 1007 psCode.size()));
862 SkPDFStream* result = new SkPDFStream(funcData.get()); 1008 SkPDFStream* result = new SkPDFStream(funcData.get());
863 result->insertInt("FunctionType", 4); 1009 result->insertInt("FunctionType", 4);
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
949 SkShader::BitmapType bitmapType; 1095 SkShader::BitmapType bitmapType;
950 SkMatrix matrix; 1096 SkMatrix matrix;
951 bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes); 1097 bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes);
952 if (bitmapType != SkShader::kDefault_BitmapType) { 1098 if (bitmapType != SkShader::kDefault_BitmapType) {
953 fImage.reset(); 1099 fImage.reset();
954 return; 1100 return;
955 } 1101 }
956 SkASSERT(matrix.isIdentity()); 1102 SkASSERT(matrix.isIdentity());
957 fPixelGeneration = fImage.getGenerationID(); 1103 fPixelGeneration = fImage.getGenerationID();
958 } else { 1104 } else {
959 fColorData.set(sk_malloc_throw( 1105 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); 1106 shader.asAGradient(&fInfo);
965 } 1107 }
966 } 1108 }
1109
1110 SkPDFShader::State::State(const SkPDFShader::State& other)
1111 : fType(other.fType),
1112 fCanvasTransform(other.fCanvasTransform),
1113 fShaderTransform(other.fShaderTransform),
1114 fBBox(other.fBBox)
1115 {
1116 // Only gradients supported for now, since that is all that is used.
1117 // If needed, image state copy constructor can be added here later.
1118 SkASSERT(fType != SkShader::kNone_GradientType);
1119
1120 if (fType != SkShader::kNone_GradientType) {
1121 fInfo = other.fInfo;
1122
1123 AllocateGradientInfoStorage();
1124 for (int i = 0; i < fInfo.fColorCount; i++) {
1125 fInfo.fColors[i] = other.fInfo.fColors[i];
1126 fInfo.fColorOffsets[i] = other.fInfo.fColorOffsets[i];
1127 }
1128 }
1129 }
1130
1131 /**
1132 * Create a copy of this gradient state with alpha assigned to RGB luminousity.
1133 * Only valid for gradient states.
1134 */
1135 SkPDFShader::State* SkPDFShader::State::CreateAlphaToLuminosityState() const {
1136 SkASSERT(fType != SkShader::kNone_GradientType);
1137
1138 SkPDFShader::State* newState = new SkPDFShader::State(*this);
1139
1140 for (int i = 0; i < fInfo.fColorCount; i++) {
1141 SkAlpha alpha = SkColorGetA(fInfo.fColors[i]);
1142 newState->fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha);
1143 }
1144
1145 return newState;
1146 }
1147
1148 /**
1149 * Create a copy of this gradient state with alpha set to fully opaque
1150 * Only valid for gradient states.
1151 */
1152 SkPDFShader::State* SkPDFShader::State::CreateOpaqueState() const {
1153 SkASSERT(fType != SkShader::kNone_GradientType);
1154
1155 SkPDFShader::State* newState = new SkPDFShader::State(*this);
1156 SkAlpha opaque = SkColorGetA(SK_ColorBLACK);
1157 for (int i = 0; i < fInfo.fColorCount; i++) {
1158 newState->fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i], opaque);
1159 }
1160
1161 return newState;
1162 }
1163
1164 /**
1165 * Returns true if state is a gradient and the gradient has alpha.
1166 */
1167 bool SkPDFShader::State::GradientHasAlpha() const {
1168 if (fType == SkShader::kNone_GradientType) {
1169 return false;
1170 }
1171
1172 SkAlpha opaque = SkColorGetA(SK_ColorBLACK);
1173 for (int i = 0; i < fInfo.fColorCount; i++) {
1174 SkAlpha alpha = SkColorGetA(fInfo.fColors[i]);
1175 if (alpha != opaque) {
1176 return true;
1177 }
1178 }
1179 return false;
1180 }
1181
1182 void SkPDFShader::State::AllocateGradientInfoStorage() {
1183 fColorData.set(sk_malloc_throw(
1184 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar))));
1185 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get());
1186 fInfo.fColorOffsets =
1187 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount);
1188 }
OLDNEW
« src/pdf/SkPDFShader.h ('K') | « src/pdf/SkPDFShader.h ('k') | src/pdf/SkPDFUtils.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698