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 |
839 SkMatrix unflip; | 845 const SkBitmap* image = &fState.get()->fImage; |
840 unflip.setTranslate(0, SkScalarRoundToScalar(surfaceBBox.height())); | 846 SkRect bitmapBounds; |
841 unflip.preScale(SK_Scalar1, -SK_Scalar1); | 847 image->getBounds(&bitmapBounds); |
842 SkISize size = SkISize::Make(SkScalarRound(surfaceBBox.width()), | |
843 SkScalarRound(surfaceBBox.height())); | |
844 SkPDFDevice pattern(size, size, unflip); | |
845 SkCanvas canvas(&pattern); | |
846 canvas.translate(-surfaceBBox.fLeft, -surfaceBBox.fTop); | |
847 finalMatrix.preTranslate(surfaceBBox.fLeft, surfaceBBox.fTop); | |
848 | 848 |
849 const SkBitmap* image = &fState.get()->fImage; | 849 // For tiling modes, the bounds should be extended to include the bitmap, |
850 SkScalar width = SkIntToScalar(image->width()); | 850 // otherwise the bitmap gets clipped out and the shader is empty and awful. |
851 SkScalar height = SkIntToScalar(image->height()); | 851 // For clamp modes, we're only interested in the clip region, whether |
| 852 // or not the main bitmap is in it. |
852 SkShader::TileMode tileModes[2]; | 853 SkShader::TileMode tileModes[2]; |
853 tileModes[0] = fState.get()->fImageTileModes[0]; | 854 tileModes[0] = fState.get()->fImageTileModes[0]; |
854 tileModes[1] = fState.get()->fImageTileModes[1]; | 855 tileModes[1] = fState.get()->fImageTileModes[1]; |
| 856 if (tileModes[0] != SkShader::kClamp_TileMode || |
| 857 tileModes[1] != SkShader::kClamp_TileMode) { |
| 858 deviceBounds.join(bitmapBounds); |
| 859 } |
855 | 860 |
| 861 SkMatrix unflip; |
| 862 unflip.setTranslate(0, SkScalarRoundToScalar(deviceBounds.height())); |
| 863 unflip.preScale(SK_Scalar1, -SK_Scalar1); |
| 864 SkISize size = SkISize::Make(SkScalarRound(deviceBounds.width()), |
| 865 SkScalarRound(deviceBounds.height())); |
| 866 SkPDFDevice pattern(size, size, unflip); |
| 867 SkCanvas canvas(&pattern); |
| 868 |
| 869 SkRect patternBBox; |
| 870 image->getBounds(&patternBBox); |
| 871 |
| 872 // Translate the canvas so that the bitmap origin is at (0, 0). |
| 873 canvas.translate(-deviceBounds.left(), -deviceBounds.top()); |
| 874 patternBBox.offset(-deviceBounds.left(), -deviceBounds.top()); |
| 875 // Undo the translation in the final matrix |
| 876 finalMatrix.preTranslate(deviceBounds.left(), deviceBounds.top()); |
| 877 |
| 878 // If the bitmap is out of bounds (i.e. clamp mode where we only see the |
| 879 // stretched sides), canvas will clip this out and the extraneous data |
| 880 // won't be saved to the PDF. |
856 canvas.drawBitmap(*image, 0, 0); | 881 canvas.drawBitmap(*image, 0, 0); |
857 SkRect patternBBox = SkRect::MakeXYWH(-surfaceBBox.fLeft, -surfaceBBox.fTop, | 882 |
858 width, height); | 883 SkScalar width = SkIntToScalar(image->width()); |
| 884 SkScalar height = SkIntToScalar(image->height()); |
859 | 885 |
860 // Tiling is implied. First we handle mirroring. | 886 // Tiling is implied. First we handle mirroring. |
861 if (tileModes[0] == SkShader::kMirror_TileMode) { | 887 if (tileModes[0] == SkShader::kMirror_TileMode) { |
862 SkMatrix xMirror; | 888 SkMatrix xMirror; |
863 xMirror.setScale(-1, 1); | 889 xMirror.setScale(-1, 1); |
864 xMirror.postTranslate(2 * width, 0); | 890 xMirror.postTranslate(2 * width, 0); |
865 canvas.drawBitmapMatrix(*image, xMirror); | 891 canvas.drawBitmapMatrix(*image, xMirror); |
866 patternBBox.fRight += width; | 892 patternBBox.fRight += width; |
867 } | 893 } |
868 if (tileModes[1] == SkShader::kMirror_TileMode) { | 894 if (tileModes[1] == SkShader::kMirror_TileMode) { |
(...skipping 13 matching lines...) Expand all Loading... |
882 | 908 |
883 // Then handle Clamping, which requires expanding the pattern canvas to | 909 // Then handle Clamping, which requires expanding the pattern canvas to |
884 // cover the entire surfaceBBox. | 910 // cover the entire surfaceBBox. |
885 | 911 |
886 // If both x and y are in clamp mode, we start by filling in the corners. | 912 // 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.) | 913 // (Which are just a rectangles of the corner colors.) |
888 if (tileModes[0] == SkShader::kClamp_TileMode && | 914 if (tileModes[0] == SkShader::kClamp_TileMode && |
889 tileModes[1] == SkShader::kClamp_TileMode) { | 915 tileModes[1] == SkShader::kClamp_TileMode) { |
890 SkPaint paint; | 916 SkPaint paint; |
891 SkRect rect; | 917 SkRect rect; |
892 rect = SkRect::MakeLTRB(surfaceBBox.fLeft, surfaceBBox.fTop, 0, 0); | 918 rect = SkRect::MakeLTRB(deviceBounds.left(), deviceBounds.top(), 0, 0); |
893 if (!rect.isEmpty()) { | 919 if (!rect.isEmpty()) { |
894 paint.setColor(image->getColor(0, 0)); | 920 paint.setColor(image->getColor(0, 0)); |
895 canvas.drawRect(rect, paint); | 921 canvas.drawRect(rect, paint); |
896 } | 922 } |
897 | 923 |
898 rect = SkRect::MakeLTRB(width, surfaceBBox.fTop, surfaceBBox.fRight, 0); | 924 rect = SkRect::MakeLTRB(width, deviceBounds.top(), |
| 925 deviceBounds.right(), 0); |
899 if (!rect.isEmpty()) { | 926 if (!rect.isEmpty()) { |
900 paint.setColor(image->getColor(image->width() - 1, 0)); | 927 paint.setColor(image->getColor(image->width() - 1, 0)); |
901 canvas.drawRect(rect, paint); | 928 canvas.drawRect(rect, paint); |
902 } | 929 } |
903 | 930 |
904 rect = SkRect::MakeLTRB(width, height, surfaceBBox.fRight, | 931 rect = SkRect::MakeLTRB(width, height, |
905 surfaceBBox.fBottom); | 932 deviceBounds.right(), deviceBounds.bottom()); |
906 if (!rect.isEmpty()) { | 933 if (!rect.isEmpty()) { |
907 paint.setColor(image->getColor(image->width() - 1, | 934 paint.setColor(image->getColor(image->width() - 1, |
908 image->height() - 1)); | 935 image->height() - 1)); |
909 canvas.drawRect(rect, paint); | 936 canvas.drawRect(rect, paint); |
910 } | 937 } |
911 | 938 |
912 rect = SkRect::MakeLTRB(surfaceBBox.fLeft, height, 0, | 939 rect = SkRect::MakeLTRB(deviceBounds.left(), height, |
913 surfaceBBox.fBottom); | 940 0, deviceBounds.bottom()); |
914 if (!rect.isEmpty()) { | 941 if (!rect.isEmpty()) { |
915 paint.setColor(image->getColor(0, image->height() - 1)); | 942 paint.setColor(image->getColor(0, image->height() - 1)); |
916 canvas.drawRect(rect, paint); | 943 canvas.drawRect(rect, paint); |
917 } | 944 } |
918 } | 945 } |
919 | 946 |
920 // Then expand the left, right, top, then bottom. | 947 // Then expand the left, right, top, then bottom. |
921 if (tileModes[0] == SkShader::kClamp_TileMode) { | 948 if (tileModes[0] == SkShader::kClamp_TileMode) { |
922 SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height()); | 949 SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height()); |
923 if (surfaceBBox.fLeft < 0) { | 950 if (deviceBounds.left() < 0) { |
924 SkBitmap left; | 951 SkBitmap left; |
925 SkAssertResult(image->extractSubset(&left, subset)); | 952 SkAssertResult(image->extractSubset(&left, subset)); |
926 | 953 |
927 SkMatrix leftMatrix; | 954 SkMatrix leftMatrix; |
928 leftMatrix.setScale(-surfaceBBox.fLeft, 1); | 955 leftMatrix.setScale(-deviceBounds.left(), 1); |
929 leftMatrix.postTranslate(surfaceBBox.fLeft, 0); | 956 leftMatrix.postTranslate(deviceBounds.left(), 0); |
930 canvas.drawBitmapMatrix(left, leftMatrix); | 957 canvas.drawBitmapMatrix(left, leftMatrix); |
931 | 958 |
932 if (tileModes[1] == SkShader::kMirror_TileMode) { | 959 if (tileModes[1] == SkShader::kMirror_TileMode) { |
933 leftMatrix.postScale(SK_Scalar1, -SK_Scalar1); | 960 leftMatrix.postScale(SK_Scalar1, -SK_Scalar1); |
934 leftMatrix.postTranslate(0, 2 * height); | 961 leftMatrix.postTranslate(0, 2 * height); |
935 canvas.drawBitmapMatrix(left, leftMatrix); | 962 canvas.drawBitmapMatrix(left, leftMatrix); |
936 } | 963 } |
937 patternBBox.fLeft = 0; | 964 patternBBox.fLeft = 0; |
938 } | 965 } |
939 | 966 |
940 if (surfaceBBox.fRight > width) { | 967 if (deviceBounds.right() > width) { |
941 SkBitmap right; | 968 SkBitmap right; |
942 subset.offset(image->width() - 1, 0); | 969 subset.offset(image->width() - 1, 0); |
943 SkAssertResult(image->extractSubset(&right, subset)); | 970 SkAssertResult(image->extractSubset(&right, subset)); |
944 | 971 |
945 SkMatrix rightMatrix; | 972 SkMatrix rightMatrix; |
946 rightMatrix.setScale(surfaceBBox.fRight - width, 1); | 973 rightMatrix.setScale(deviceBounds.right() - width, 1); |
947 rightMatrix.postTranslate(width, 0); | 974 rightMatrix.postTranslate(width, 0); |
948 canvas.drawBitmapMatrix(right, rightMatrix); | 975 canvas.drawBitmapMatrix(right, rightMatrix); |
949 | 976 |
950 if (tileModes[1] == SkShader::kMirror_TileMode) { | 977 if (tileModes[1] == SkShader::kMirror_TileMode) { |
951 rightMatrix.postScale(SK_Scalar1, -SK_Scalar1); | 978 rightMatrix.postScale(SK_Scalar1, -SK_Scalar1); |
952 rightMatrix.postTranslate(0, 2 * height); | 979 rightMatrix.postTranslate(0, 2 * height); |
953 canvas.drawBitmapMatrix(right, rightMatrix); | 980 canvas.drawBitmapMatrix(right, rightMatrix); |
954 } | 981 } |
955 patternBBox.fRight = surfaceBBox.width(); | 982 patternBBox.fRight = deviceBounds.width(); |
956 } | 983 } |
957 } | 984 } |
958 | 985 |
959 if (tileModes[1] == SkShader::kClamp_TileMode) { | 986 if (tileModes[1] == SkShader::kClamp_TileMode) { |
960 SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1); | 987 SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1); |
961 if (surfaceBBox.fTop < 0) { | 988 if (deviceBounds.top() < 0) { |
962 SkBitmap top; | 989 SkBitmap top; |
963 SkAssertResult(image->extractSubset(&top, subset)); | 990 SkAssertResult(image->extractSubset(&top, subset)); |
964 | 991 |
965 SkMatrix topMatrix; | 992 SkMatrix topMatrix; |
966 topMatrix.setScale(SK_Scalar1, -surfaceBBox.fTop); | 993 topMatrix.setScale(SK_Scalar1, -deviceBounds.top()); |
967 topMatrix.postTranslate(0, surfaceBBox.fTop); | 994 topMatrix.postTranslate(0, deviceBounds.top()); |
968 canvas.drawBitmapMatrix(top, topMatrix); | 995 canvas.drawBitmapMatrix(top, topMatrix); |
969 | 996 |
970 if (tileModes[0] == SkShader::kMirror_TileMode) { | 997 if (tileModes[0] == SkShader::kMirror_TileMode) { |
971 topMatrix.postScale(-1, 1); | 998 topMatrix.postScale(-1, 1); |
972 topMatrix.postTranslate(2 * width, 0); | 999 topMatrix.postTranslate(2 * width, 0); |
973 canvas.drawBitmapMatrix(top, topMatrix); | 1000 canvas.drawBitmapMatrix(top, topMatrix); |
974 } | 1001 } |
975 patternBBox.fTop = 0; | 1002 patternBBox.fTop = 0; |
976 } | 1003 } |
977 | 1004 |
978 if (surfaceBBox.fBottom > height) { | 1005 if (deviceBounds.bottom() > height) { |
979 SkBitmap bottom; | 1006 SkBitmap bottom; |
980 subset.offset(0, image->height() - 1); | 1007 subset.offset(0, image->height() - 1); |
981 SkAssertResult(image->extractSubset(&bottom, subset)); | 1008 SkAssertResult(image->extractSubset(&bottom, subset)); |
982 | 1009 |
983 SkMatrix bottomMatrix; | 1010 SkMatrix bottomMatrix; |
984 bottomMatrix.setScale(SK_Scalar1, surfaceBBox.fBottom - height); | 1011 bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height); |
985 bottomMatrix.postTranslate(0, height); | 1012 bottomMatrix.postTranslate(0, height); |
986 canvas.drawBitmapMatrix(bottom, bottomMatrix); | 1013 canvas.drawBitmapMatrix(bottom, bottomMatrix); |
987 | 1014 |
988 if (tileModes[0] == SkShader::kMirror_TileMode) { | 1015 if (tileModes[0] == SkShader::kMirror_TileMode) { |
989 bottomMatrix.postScale(-1, 1); | 1016 bottomMatrix.postScale(-1, 1); |
990 bottomMatrix.postTranslate(2 * width, 0); | 1017 bottomMatrix.postTranslate(2 * width, 0); |
991 canvas.drawBitmapMatrix(bottom, bottomMatrix); | 1018 canvas.drawBitmapMatrix(bottom, bottomMatrix); |
992 } | 1019 } |
993 patternBBox.fBottom = surfaceBBox.height(); | 1020 patternBBox.fBottom = deviceBounds.height(); |
994 } | 1021 } |
995 } | 1022 } |
996 | 1023 |
997 // Put the canvas into the pattern stream (fContent). | 1024 // Put the canvas into the pattern stream (fContent). |
998 SkAutoTUnref<SkStream> content(pattern.content()); | 1025 SkAutoTUnref<SkStream> content(pattern.content()); |
999 setData(content.get()); | 1026 setData(content.get()); |
1000 SkPDFResourceDict* resourceDict = pattern.getResourceDict(); | 1027 SkPDFResourceDict* resourceDict = pattern.getResourceDict(); |
1001 resourceDict->getReferencedResources(fResources, &fResources, false); | 1028 resourceDict->getReferencedResources(fResources, &fResources, false); |
1002 | 1029 |
1003 populate_tiling_pattern_dict(this, patternBBox, | 1030 populate_tiling_pattern_dict(this, patternBBox, |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1183 return false; | 1210 return false; |
1184 } | 1211 } |
1185 | 1212 |
1186 void SkPDFShader::State::AllocateGradientInfoStorage() { | 1213 void SkPDFShader::State::AllocateGradientInfoStorage() { |
1187 fColorData.set(sk_malloc_throw( | 1214 fColorData.set(sk_malloc_throw( |
1188 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); | 1215 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); |
1189 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); | 1216 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); |
1190 fInfo.fColorOffsets = | 1217 fInfo.fColorOffsets = |
1191 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); | 1218 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); |
1192 } | 1219 } |
OLD | NEW |