OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 #include "SkPDFShader.h" | 10 #include "SkPDFShader.h" |
11 | 11 |
12 #include "SkCanvas.h" | 12 #include "SkCanvas.h" |
13 #include "SkData.h" | 13 #include "SkData.h" |
14 #include "SkPDFCatalog.h" | 14 #include "SkPDFCatalog.h" |
15 #include "SkPDFDevice.h" | 15 #include "SkPDFDevice.h" |
16 #include "SkPDFFormXObject.h" | 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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |