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

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

Issue 22884013: Support tiling bitmaps outside clip bounds in SkPDFImageShader (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Created 7 years, 4 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
« no previous file with comments | « no previous file | 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 "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" 16 #include "SkPDFFormXObject.h"
17 #include "SkPDFGraphicState.h" 17 #include "SkPDFGraphicState.h"
18 #include "SkPDFResourceDict.h" 18 #include "SkPDFResourceDict.h"
19 #include "SkPDFUtils.h" 19 #include "SkPDFUtils.h"
20 #include "SkScalar.h" 20 #include "SkScalar.h"
21 #include "SkStream.h" 21 #include "SkStream.h"
22 #include "SkTemplates.h" 22 #include "SkTemplates.h"
23 #include "SkThread.h" 23 #include "SkThread.h"
24 #include "SkTSet.h" 24 #include "SkTSet.h"
25 #include "SkTypes.h" 25 #include "SkTypes.h"
26 26
27 static bool transformBBox(const SkMatrix& matrix, SkRect* bbox) { 27 static bool inverseTransformBBox(const SkMatrix& matrix, SkRect* bbox) {
28 SkMatrix inverse; 28 SkMatrix inverse;
29 if (!matrix.invert(&inverse)) { 29 if (!matrix.invert(&inverse)) {
30 return false; 30 return false;
31 } 31 }
32 inverse.mapRect(bbox); 32 inverse.mapRect(bbox);
33 return true; 33 return true;
34 } 34 }
35 35
36 static void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) { 36 static void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) {
37 SkVector vec = pts[1] - pts[0]; 37 SkVector vec = pts[1] - pts[0];
(...skipping 735 matching lines...) Expand 10 before | Expand all | Expand 10 after
773 // info->fPoints to the matrix (updating bbox appropriately). Now 773 // info->fPoints to the matrix (updating bbox appropriately). Now
774 // the gradient can be drawn on on the unit segment. 774 // the gradient can be drawn on on the unit segment.
775 SkMatrix mapperMatrix; 775 SkMatrix mapperMatrix;
776 unitToPointsMatrix(transformPoints, &mapperMatrix); 776 unitToPointsMatrix(transformPoints, &mapperMatrix);
777 SkMatrix finalMatrix = fState.get()->fCanvasTransform; 777 SkMatrix finalMatrix = fState.get()->fCanvasTransform;
778 finalMatrix.preConcat(fState.get()->fShaderTransform); 778 finalMatrix.preConcat(fState.get()->fShaderTransform);
779 finalMatrix.preConcat(mapperMatrix); 779 finalMatrix.preConcat(mapperMatrix);
780 780
781 SkRect bbox; 781 SkRect bbox;
782 bbox.set(fState.get()->fBBox); 782 bbox.set(fState.get()->fBBox);
783 if (!transformBBox(finalMatrix, &bbox)) { 783 if (!inverseTransformBBox(finalMatrix, &bbox)) {
784 return; 784 return;
785 } 785 }
786 786
787 SkAutoTUnref<SkPDFArray> domain(new SkPDFArray); 787 SkAutoTUnref<SkPDFArray> domain(new SkPDFArray);
788 domain->reserve(4); 788 domain->reserve(4);
789 domain->appendScalar(bbox.fLeft); 789 domain->appendScalar(bbox.fLeft);
790 domain->appendScalar(bbox.fRight); 790 domain->appendScalar(bbox.fRight);
791 domain->appendScalar(bbox.fTop); 791 domain->appendScalar(bbox.fTop);
792 domain->appendScalar(bbox.fBottom); 792 domain->appendScalar(bbox.fBottom);
793 793
(...skipping 27 matching lines...) Expand all
821 fResources.push(function); // Pass ownership to resource list. 821 fResources.push(function); // Pass ownership to resource list.
822 822
823 insertInt("PatternType", 2); 823 insertInt("PatternType", 2);
824 insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref(); 824 insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
825 insert("Shading", pdfShader.get()); 825 insert("Shading", pdfShader.get());
826 } 826 }
827 827
828 SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) { 828 SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
829 fState.get()->fImage.lockPixels(); 829 fState.get()->fImage.lockPixels();
830 830
831 // The image shader pattern cell will be drawn into a separate device
832 // in pattern cell space (no scaling on the bitmap, though there may be
833 // translations so that all content is in the device, coordinates > 0).
834
835 // Map clip bounds to shader space to ensure the device is large enough
836 // to handle fake clamping.
831 SkMatrix finalMatrix = fState.get()->fCanvasTransform; 837 SkMatrix finalMatrix = fState.get()->fCanvasTransform;
832 finalMatrix.preConcat(fState.get()->fShaderTransform); 838 finalMatrix.preConcat(fState.get()->fShaderTransform);
833 SkRect surfaceBBox; 839 SkRect deviceBounds;
834 surfaceBBox.set(fState.get()->fBBox); 840 deviceBounds.set(fState.get()->fBBox);
835 if (!transformBBox(finalMatrix, &surfaceBBox)) { 841 if (!inverseTransformBBox(finalMatrix, &deviceBounds)) {
836 return; 842 return;
837 } 843 }
838 844
845 // Ensure the device bounds include the pattern cell as tiling theoretically
846 // extends out to infinity. If the device size is too small, the pattern
847 // cell bitmap will be clipped out, and the shader will look awful.
848 const SkBitmap* image = &fState.get()->fImage;
vandebo (ex-Chrome) 2013/08/20 17:22:19 I think you don't want to do this for clamp mode.
ducky 2013/08/21 00:44:08 Done.
849 SkRect bitmapBounds;
850 image->getBounds(&bitmapBounds);
851 deviceBounds.join(bitmapBounds);
852
839 SkMatrix unflip; 853 SkMatrix unflip;
840 unflip.setTranslate(0, SkScalarRoundToScalar(surfaceBBox.height())); 854 unflip.setTranslate(0, SkScalarRoundToScalar(deviceBounds.height()));
841 unflip.preScale(SK_Scalar1, -SK_Scalar1); 855 unflip.preScale(SK_Scalar1, -SK_Scalar1);
842 SkISize size = SkISize::Make(SkScalarRound(surfaceBBox.width()), 856 SkISize size = SkISize::Make(SkScalarRound(deviceBounds.width()),
843 SkScalarRound(surfaceBBox.height())); 857 SkScalarRound(deviceBounds.height()));
844 SkPDFDevice pattern(size, size, unflip); 858 SkPDFDevice pattern(size, size, unflip);
845 SkCanvas canvas(&pattern); 859 SkCanvas canvas(&pattern);
846 canvas.translate(-surfaceBBox.fLeft, -surfaceBBox.fTop);
847 finalMatrix.preTranslate(surfaceBBox.fLeft, surfaceBBox.fTop);
848 860
849 const SkBitmap* image = &fState.get()->fImage; 861 SkRect patternBBox;
850 SkScalar width = SkIntToScalar(image->width()); 862 image->getBounds(&patternBBox);
851 SkScalar height = SkIntToScalar(image->height()); 863 // Translate canvas origin to bitmap origin so all coordinates are > 0
864 // (inside device clip bounds).
865 if (deviceBounds.left() < 0 || deviceBounds.top() < 0) {
vandebo (ex-Chrome) 2013/08/20 17:22:19 Why do this conditionally? What if the pattern is
ducky 2013/08/21 00:44:08 The bitmap origin is at (0, 0), so the joined rect
866 canvas.translate(-deviceBounds.left(), -deviceBounds.top());
867 patternBBox.offset(-deviceBounds.left(), -deviceBounds.top());
868 // Undo the translation in the final matrix
869 finalMatrix.preTranslate(deviceBounds.left(), deviceBounds.top());
870 }
871
872 canvas.drawBitmap(*image, 0, 0);
873
874 SkScalar width = image->width();
875 SkScalar height = image->height();
852 SkShader::TileMode tileModes[2]; 876 SkShader::TileMode tileModes[2];
853 tileModes[0] = fState.get()->fImageTileModes[0]; 877 tileModes[0] = fState.get()->fImageTileModes[0];
854 tileModes[1] = fState.get()->fImageTileModes[1]; 878 tileModes[1] = fState.get()->fImageTileModes[1];
855 879
856 canvas.drawBitmap(*image, 0, 0);
857 SkRect patternBBox = SkRect::MakeXYWH(-surfaceBBox.fLeft, -surfaceBBox.fTop,
858 width, height);
859
860 // Tiling is implied. First we handle mirroring. 880 // Tiling is implied. First we handle mirroring.
861 if (tileModes[0] == SkShader::kMirror_TileMode) { 881 if (tileModes[0] == SkShader::kMirror_TileMode) {
862 SkMatrix xMirror; 882 SkMatrix xMirror;
863 xMirror.setScale(-1, 1); 883 xMirror.setScale(-1, 1);
864 xMirror.postTranslate(2 * width, 0); 884 xMirror.postTranslate(2 * width, 0);
865 canvas.drawBitmapMatrix(*image, xMirror); 885 canvas.drawBitmapMatrix(*image, xMirror);
866 patternBBox.fRight += width; 886 patternBBox.fRight += width;
867 } 887 }
868 if (tileModes[1] == SkShader::kMirror_TileMode) { 888 if (tileModes[1] == SkShader::kMirror_TileMode) {
869 SkMatrix yMirror; 889 SkMatrix yMirror;
(...skipping 12 matching lines...) Expand all
882 902
883 // Then handle Clamping, which requires expanding the pattern canvas to 903 // Then handle Clamping, which requires expanding the pattern canvas to
884 // cover the entire surfaceBBox. 904 // cover the entire surfaceBBox.
885 905
886 // If both x and y are in clamp mode, we start by filling in the corners. 906 // If both x and y are in clamp mode, we start by filling in the corners.
887 // (Which are just a rectangles of the corner colors.) 907 // (Which are just a rectangles of the corner colors.)
888 if (tileModes[0] == SkShader::kClamp_TileMode && 908 if (tileModes[0] == SkShader::kClamp_TileMode &&
889 tileModes[1] == SkShader::kClamp_TileMode) { 909 tileModes[1] == SkShader::kClamp_TileMode) {
890 SkPaint paint; 910 SkPaint paint;
891 SkRect rect; 911 SkRect rect;
892 rect = SkRect::MakeLTRB(surfaceBBox.fLeft, surfaceBBox.fTop, 0, 0); 912 rect = SkRect::MakeLTRB(deviceBounds.left(), deviceBounds.top(), 0, 0);
893 if (!rect.isEmpty()) { 913 if (!rect.isEmpty()) {
894 paint.setColor(image->getColor(0, 0)); 914 paint.setColor(image->getColor(0, 0));
895 canvas.drawRect(rect, paint); 915 canvas.drawRect(rect, paint);
896 } 916 }
897 917
898 rect = SkRect::MakeLTRB(width, surfaceBBox.fTop, surfaceBBox.fRight, 0); 918 rect = SkRect::MakeLTRB(width, deviceBounds.top(),
919 deviceBounds.right(), 0);
899 if (!rect.isEmpty()) { 920 if (!rect.isEmpty()) {
900 paint.setColor(image->getColor(image->width() - 1, 0)); 921 paint.setColor(image->getColor(image->width() - 1, 0));
901 canvas.drawRect(rect, paint); 922 canvas.drawRect(rect, paint);
902 } 923 }
903 924
904 rect = SkRect::MakeLTRB(width, height, surfaceBBox.fRight, 925 rect = SkRect::MakeLTRB(width, height,
905 surfaceBBox.fBottom); 926 deviceBounds.right(), deviceBounds.bottom());
906 if (!rect.isEmpty()) { 927 if (!rect.isEmpty()) {
907 paint.setColor(image->getColor(image->width() - 1, 928 paint.setColor(image->getColor(image->width() - 1,
908 image->height() - 1)); 929 image->height() - 1));
909 canvas.drawRect(rect, paint); 930 canvas.drawRect(rect, paint);
910 } 931 }
911 932
912 rect = SkRect::MakeLTRB(surfaceBBox.fLeft, height, 0, 933 rect = SkRect::MakeLTRB(deviceBounds.left(), height,
913 surfaceBBox.fBottom); 934 0, deviceBounds.bottom());
914 if (!rect.isEmpty()) { 935 if (!rect.isEmpty()) {
915 paint.setColor(image->getColor(0, image->height() - 1)); 936 paint.setColor(image->getColor(0, image->height() - 1));
916 canvas.drawRect(rect, paint); 937 canvas.drawRect(rect, paint);
917 } 938 }
918 } 939 }
919 940
920 // Then expand the left, right, top, then bottom. 941 // Then expand the left, right, top, then bottom.
921 if (tileModes[0] == SkShader::kClamp_TileMode) { 942 if (tileModes[0] == SkShader::kClamp_TileMode) {
922 SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height()); 943 SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height());
923 if (surfaceBBox.fLeft < 0) { 944 if (deviceBounds.left() < 0) {
924 SkBitmap left; 945 SkBitmap left;
925 SkAssertResult(image->extractSubset(&left, subset)); 946 SkAssertResult(image->extractSubset(&left, subset));
926 947
927 SkMatrix leftMatrix; 948 SkMatrix leftMatrix;
928 leftMatrix.setScale(-surfaceBBox.fLeft, 1); 949 leftMatrix.setScale(-deviceBounds.left(), 1);
929 leftMatrix.postTranslate(surfaceBBox.fLeft, 0); 950 leftMatrix.postTranslate(deviceBounds.left(), 0);
930 canvas.drawBitmapMatrix(left, leftMatrix); 951 canvas.drawBitmapMatrix(left, leftMatrix);
931 952
932 if (tileModes[1] == SkShader::kMirror_TileMode) { 953 if (tileModes[1] == SkShader::kMirror_TileMode) {
933 leftMatrix.postScale(SK_Scalar1, -SK_Scalar1); 954 leftMatrix.postScale(SK_Scalar1, -SK_Scalar1);
934 leftMatrix.postTranslate(0, 2 * height); 955 leftMatrix.postTranslate(0, 2 * height);
935 canvas.drawBitmapMatrix(left, leftMatrix); 956 canvas.drawBitmapMatrix(left, leftMatrix);
936 } 957 }
937 patternBBox.fLeft = 0; 958 patternBBox.fLeft = 0;
938 } 959 }
939 960
940 if (surfaceBBox.fRight > width) { 961 if (deviceBounds.right() > width) {
941 SkBitmap right; 962 SkBitmap right;
942 subset.offset(image->width() - 1, 0); 963 subset.offset(image->width() - 1, 0);
943 SkAssertResult(image->extractSubset(&right, subset)); 964 SkAssertResult(image->extractSubset(&right, subset));
944 965
945 SkMatrix rightMatrix; 966 SkMatrix rightMatrix;
946 rightMatrix.setScale(surfaceBBox.fRight - width, 1); 967 rightMatrix.setScale(deviceBounds.right() - width, 1);
947 rightMatrix.postTranslate(width, 0); 968 rightMatrix.postTranslate(width, 0);
948 canvas.drawBitmapMatrix(right, rightMatrix); 969 canvas.drawBitmapMatrix(right, rightMatrix);
949 970
950 if (tileModes[1] == SkShader::kMirror_TileMode) { 971 if (tileModes[1] == SkShader::kMirror_TileMode) {
951 rightMatrix.postScale(SK_Scalar1, -SK_Scalar1); 972 rightMatrix.postScale(SK_Scalar1, -SK_Scalar1);
952 rightMatrix.postTranslate(0, 2 * height); 973 rightMatrix.postTranslate(0, 2 * height);
953 canvas.drawBitmapMatrix(right, rightMatrix); 974 canvas.drawBitmapMatrix(right, rightMatrix);
954 } 975 }
955 patternBBox.fRight = surfaceBBox.width(); 976 patternBBox.fRight = deviceBounds.width();
956 } 977 }
957 } 978 }
958 979
959 if (tileModes[1] == SkShader::kClamp_TileMode) { 980 if (tileModes[1] == SkShader::kClamp_TileMode) {
960 SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1); 981 SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1);
961 if (surfaceBBox.fTop < 0) { 982 if (deviceBounds.top() < 0) {
962 SkBitmap top; 983 SkBitmap top;
963 SkAssertResult(image->extractSubset(&top, subset)); 984 SkAssertResult(image->extractSubset(&top, subset));
964 985
965 SkMatrix topMatrix; 986 SkMatrix topMatrix;
966 topMatrix.setScale(SK_Scalar1, -surfaceBBox.fTop); 987 topMatrix.setScale(SK_Scalar1, -deviceBounds.top());
967 topMatrix.postTranslate(0, surfaceBBox.fTop); 988 topMatrix.postTranslate(0, deviceBounds.top());
968 canvas.drawBitmapMatrix(top, topMatrix); 989 canvas.drawBitmapMatrix(top, topMatrix);
969 990
970 if (tileModes[0] == SkShader::kMirror_TileMode) { 991 if (tileModes[0] == SkShader::kMirror_TileMode) {
971 topMatrix.postScale(-1, 1); 992 topMatrix.postScale(-1, 1);
972 topMatrix.postTranslate(2 * width, 0); 993 topMatrix.postTranslate(2 * width, 0);
973 canvas.drawBitmapMatrix(top, topMatrix); 994 canvas.drawBitmapMatrix(top, topMatrix);
974 } 995 }
975 patternBBox.fTop = 0; 996 patternBBox.fTop = 0;
976 } 997 }
977 998
978 if (surfaceBBox.fBottom > height) { 999 if (deviceBounds.bottom() > height) {
979 SkBitmap bottom; 1000 SkBitmap bottom;
980 subset.offset(0, image->height() - 1); 1001 subset.offset(0, image->height() - 1);
981 SkAssertResult(image->extractSubset(&bottom, subset)); 1002 SkAssertResult(image->extractSubset(&bottom, subset));
982 1003
983 SkMatrix bottomMatrix; 1004 SkMatrix bottomMatrix;
984 bottomMatrix.setScale(SK_Scalar1, surfaceBBox.fBottom - height); 1005 bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height);
985 bottomMatrix.postTranslate(0, height); 1006 bottomMatrix.postTranslate(0, height);
986 canvas.drawBitmapMatrix(bottom, bottomMatrix); 1007 canvas.drawBitmapMatrix(bottom, bottomMatrix);
987 1008
988 if (tileModes[0] == SkShader::kMirror_TileMode) { 1009 if (tileModes[0] == SkShader::kMirror_TileMode) {
989 bottomMatrix.postScale(-1, 1); 1010 bottomMatrix.postScale(-1, 1);
990 bottomMatrix.postTranslate(2 * width, 0); 1011 bottomMatrix.postTranslate(2 * width, 0);
991 canvas.drawBitmapMatrix(bottom, bottomMatrix); 1012 canvas.drawBitmapMatrix(bottom, bottomMatrix);
992 } 1013 }
993 patternBBox.fBottom = surfaceBBox.height(); 1014 patternBBox.fBottom = deviceBounds.height();
994 } 1015 }
995 } 1016 }
996 1017
997 // Put the canvas into the pattern stream (fContent). 1018 // Put the canvas into the pattern stream (fContent).
998 SkAutoTUnref<SkStream> content(pattern.content()); 1019 SkAutoTUnref<SkStream> content(pattern.content());
999 setData(content.get()); 1020 setData(content.get());
1000 SkPDFResourceDict* resourceDict = pattern.getResourceDict(); 1021 SkPDFResourceDict* resourceDict = pattern.getResourceDict();
1001 resourceDict->getReferencedResources(fResources, &fResources, false); 1022 resourceDict->getReferencedResources(fResources, &fResources, false);
1002 1023
1003 populate_tiling_pattern_dict(this, patternBBox, 1024 populate_tiling_pattern_dict(this, patternBBox,
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
1183 return false; 1204 return false;
1184 } 1205 }
1185 1206
1186 void SkPDFShader::State::AllocateGradientInfoStorage() { 1207 void SkPDFShader::State::AllocateGradientInfoStorage() {
1187 fColorData.set(sk_malloc_throw( 1208 fColorData.set(sk_malloc_throw(
1188 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); 1209 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar))));
1189 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); 1210 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get());
1190 fInfo.fColorOffsets = 1211 fInfo.fColorOffsets =
1191 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); 1212 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount);
1192 } 1213 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698