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

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: Fix GM slide nits 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 | « gyp/gmslides.gypi ('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 "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
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
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
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 }
OLDNEW
« no previous file with comments | « gyp/gmslides.gypi ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698