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

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

Issue 1925233003: SkPDF: Use type 2/3 shading for gradient shaders (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: removed whitespace Created 4 years, 6 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
« no previous file with comments | « AUTHORS ('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 * Copyright 2011 Google Inc. 2 * Copyright 2011 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 8
9 #include "SkPDFShader.h" 9 #include "SkPDFShader.h"
10 10
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 colorData[2][r,g,b]); 115 colorData[2][r,g,b]);
116 } else { 116 } else {
117 117
118 ... } else { 118 ... } else {
119 return colorData[info.fColorCount - 1][r,g,b]; 119 return colorData[info.fColorCount - 1][r,g,b];
120 } 120 }
121 ... 121 ...
122 } 122 }
123 } 123 }
124 */ 124 */
125 static const int kColorComponents = 3;
126 typedef SkScalar ColorTuple[kColorComponents];
125 static void gradientFunctionCode(const SkShader::GradientInfo& info, 127 static void gradientFunctionCode(const SkShader::GradientInfo& info,
126 SkDynamicMemoryWStream* result) { 128 SkDynamicMemoryWStream* result) {
127 /* We want to linearly interpolate from the previous color to the next. 129 /* We want to linearly interpolate from the previous color to the next.
128 Scale the colors from 0..255 to 0..1 and determine the multipliers 130 Scale the colors from 0..255 to 0..1 and determine the multipliers
129 for interpolation. 131 for interpolation.
130 C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}. 132 C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}.
131 */ 133 */
132 static const int kColorComponents = 3; 134
133 typedef SkScalar ColorTuple[kColorComponents];
134 SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount); 135 SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount);
135 ColorTuple *colorData = colorDataAlloc.get(); 136 ColorTuple *colorData = colorDataAlloc.get();
136 const SkScalar scale = SkScalarInvert(SkIntToScalar(255)); 137 const SkScalar scale = SkScalarInvert(SkIntToScalar(255));
137 for (int i = 0; i < info.fColorCount; i++) { 138 for (int i = 0; i < info.fColorCount; i++) {
138 colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale); 139 colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale);
139 colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale); 140 colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale);
140 colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale); 141 colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale);
141 } 142 }
142 143
143 // Clamp the initial color. 144 // Clamp the initial color.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 result->writeText(" "); 177 result->writeText(" ");
177 SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][1], result); 178 SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][1], result);
178 result->writeText(" "); 179 result->writeText(" ");
179 SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][2], result); 180 SkPDFUtils::AppendScalar(colorData[info.fColorCount - 1][2], result);
180 181
181 for (int i = 0 ; i < gradients + 1; i++) { 182 for (int i = 0 ; i < gradients + 1; i++) {
182 result->writeText("} ifelse\n"); 183 result->writeText("} ifelse\n");
183 } 184 }
184 } 185 }
185 186
187 static sk_sp<SkPDFDict> createInterpolationFunction(const ColorTuple& color1,
188 const ColorTuple& color2) {
189 auto retval = sk_make_sp<SkPDFDict>();
190
191 auto c0 = sk_make_sp<SkPDFArray>();
192 c0->appendScalar(color1[0]);
193 c0->appendScalar(color1[1]);
194 c0->appendScalar(color1[2]);
195 retval->insertObject("C0", std::move(c0));
196
197 auto c1 = sk_make_sp<SkPDFArray>();
198 c1->appendScalar(color2[0]);
199 c1->appendScalar(color2[1]);
200 c1->appendScalar(color2[2]);
201 retval->insertObject("C1", std::move(c1));
202
203 auto domain = sk_make_sp<SkPDFArray>();
204 domain->appendScalar(0);
205 domain->appendScalar(1.0f);
206 retval->insertObject("Domain", std::move(domain));
207
208 retval->insertInt("FunctionType", 2);
209 retval->insertScalar("N", 1.0f);
210
211 return retval;
212 }
213
214 static sk_sp<SkPDFDict> gradientStitchCode(const SkShader::GradientInfo& info) {
215 auto retval = sk_make_sp<SkPDFDict>();
216
217 // normalize color stops
218 int colorCount = info.fColorCount;
219 SkTDArray<SkColor> colors(info.fColors, colorCount);
220 SkTDArray<SkScalar> colorOffsets(info.fColorOffsets, colorCount);
221
222 int i = 1;
223 while (i < colorCount - 1) {
224 // ensure stops are in order
225 if (colorOffsets[i - 1] > colorOffsets[i]) {
226 colorOffsets[i] = colorOffsets[i - 1];
227 }
228
229 // remove points that are between 2 coincident points
230 if ((colorOffsets[i - 1] == colorOffsets[i]) && (colorOffsets[i] == colo rOffsets[i + 1])) {
231 colorCount -= 1;
232 colors.remove(i);
233 colorOffsets.remove(i);
234 } else {
235 i++;
236 }
237 }
238 // find coincident points and slightly move them over
239 for (i = 1; i < colorCount - 1; i++) {
240 if (colorOffsets[i - 1] == colorOffsets[i]) {
241 colorOffsets[i] += 0.00001f;
242 }
243 }
244 // check if last 2 stops coincide
245 if (colorOffsets[i - 1] == colorOffsets[i]) {
246 colorOffsets[i - 1] -= 0.00001f;
247 }
248
249 SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(colorCount);
250 ColorTuple *colorData = colorDataAlloc.get();
251 const SkScalar scale = SkScalarInvert(SkIntToScalar(255));
252 for (int i = 0; i < colorCount; i++) {
253 colorData[i][0] = SkScalarMul(SkColorGetR(colors[i]), scale);
254 colorData[i][1] = SkScalarMul(SkColorGetG(colors[i]), scale);
255 colorData[i][2] = SkScalarMul(SkColorGetB(colors[i]), scale);
256 }
257
258 // no need for a stitch function if there are only 2 stops.
259 if (colorCount == 2)
260 return createInterpolationFunction(colorData[0], colorData[1]);
261
262 auto encode = sk_make_sp<SkPDFArray>();
263 auto bounds = sk_make_sp<SkPDFArray>();
264 auto functions = sk_make_sp<SkPDFArray>();
265
266 auto domain = sk_make_sp<SkPDFArray>();
267 domain->appendScalar(0);
268 domain->appendScalar(1.0f);
269 retval->insertObject("Domain", std::move(domain));
270 retval->insertInt("FunctionType", 3);
271
272 for (int i = 1; i < colorCount; i++) {
273 if (i > 1) {
274 bounds->appendScalar(colorOffsets[i-1]);
275 }
276
277 encode->appendScalar(0);
278 encode->appendScalar(1.0f);
279
280 functions->appendObject(createInterpolationFunction(colorData[i-1], colo rData[i]));
281 }
282
283 retval->insertObject("Encode", std::move(encode));
284 retval->insertObject("Bounds", std::move(bounds));
285 retval->insertObject("Functions", std::move(functions));
286
287 return retval;
288 }
289
186 /* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */ 290 /* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */
187 static void tileModeCode(SkShader::TileMode mode, 291 static void tileModeCode(SkShader::TileMode mode,
188 SkDynamicMemoryWStream* result) { 292 SkDynamicMemoryWStream* result) {
189 if (mode == SkShader::kRepeat_TileMode) { 293 if (mode == SkShader::kRepeat_TileMode) {
190 result->writeText("dup truncate sub\n"); // Get the fractional part. 294 result->writeText("dup truncate sub\n"); // Get the fractional part.
191 result->writeText("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1) 295 result->writeText("dup 0 le {1 add} if\n"); // Map (-1,0) => (0,1)
192 return; 296 return;
193 } 297 }
194 298
195 if (mode == SkShader::kMirror_TileMode) { 299 if (mode == SkShader::kMirror_TileMode) {
(...skipping 502 matching lines...) Expand 10 before | Expand all | Expand 10 after
698 std::unique_ptr<SkStreamAsset> psCode, 802 std::unique_ptr<SkStreamAsset> psCode,
699 SkPDFArray* domain, 803 SkPDFArray* domain,
700 sk_sp<SkPDFObject> range) { 804 sk_sp<SkPDFObject> range) {
701 auto result = sk_make_sp<SkPDFStream>(psCode.get()); 805 auto result = sk_make_sp<SkPDFStream>(psCode.get());
702 result->insertInt("FunctionType", 4); 806 result->insertInt("FunctionType", 4);
703 result->insertObject("Domain", sk_ref_sp(domain)); 807 result->insertObject("Domain", sk_ref_sp(domain));
704 result->insertObject("Range", std::move(range)); 808 result->insertObject("Range", std::move(range));
705 return result; 809 return result;
706 } 810 }
707 811
812 // catch cases where the inner just touches the outer circle
813 // and make the inner circle just inside the outer one to match raster
814 static void FixUpRadius(const SkPoint& p1, SkScalar& r1, const SkPoint& p2, SkSc alar& r2) {
815 // detect touching circles
816 SkScalar distance = SkPoint::Distance(p1, p2);
817 SkScalar subtractRadii = fabs(r1 - r2);
818 if (fabs(distance - subtractRadii) < 0.002f) {
819 if (r1 > r2) {
820 r1 += 0.002f;
821 } else {
822 r2 += 0.002f;
823 }
824 }
825 }
826
708 SkPDFFunctionShader* SkPDFFunctionShader::Create( 827 SkPDFFunctionShader* SkPDFFunctionShader::Create(
709 SkPDFCanon* canon, std::unique_ptr<SkPDFShader::State>* autoState) { 828 SkPDFCanon* canon, std::unique_ptr<SkPDFShader::State>* autoState) {
710 const SkPDFShader::State& state = **autoState; 829 const SkPDFShader::State& state = **autoState;
711 830
712 void (*codeFunction)(const SkShader::GradientInfo& info, 831 void (*codeFunction)(const SkShader::GradientInfo& info,
713 const SkMatrix& perspectiveRemover, 832 const SkMatrix& perspectiveRemover,
714 SkDynamicMemoryWStream* function) = nullptr; 833 SkDynamicMemoryWStream* function) = nullptr;
715 SkPoint transformPoints[2]; 834 SkPoint transformPoints[2];
716
717 // Depending on the type of the gradient, we want to transform the
718 // coordinate space in different ways.
719 const SkShader::GradientInfo* info = &state.fInfo; 835 const SkShader::GradientInfo* info = &state.fInfo;
720 transformPoints[0] = info->fPoint[0];
721 transformPoints[1] = info->fPoint[1];
722 switch (state.fType) {
723 case SkShader::kLinear_GradientType:
724 codeFunction = &linearCode;
725 break;
726 case SkShader::kRadial_GradientType:
727 transformPoints[1] = transformPoints[0];
728 transformPoints[1].fX += info->fRadius[0];
729 codeFunction = &radialCode;
730 break;
731 case SkShader::kConical_GradientType: {
732 transformPoints[1] = transformPoints[0];
733 transformPoints[1].fX += SK_Scalar1;
734 codeFunction = &twoPointConicalCode;
735 break;
736 }
737 case SkShader::kSweep_GradientType:
738 transformPoints[1] = transformPoints[0];
739 transformPoints[1].fX += SK_Scalar1;
740 codeFunction = &sweepCode;
741 break;
742 case SkShader::kColor_GradientType:
743 case SkShader::kNone_GradientType:
744 default:
745 return nullptr;
746 }
747
748 // Move any scaling (assuming a unit gradient) or translation
749 // (and rotation for linear gradient), of the final gradient from
750 // info->fPoints to the matrix (updating bbox appropriately). Now
751 // the gradient can be drawn on on the unit segment.
752 SkMatrix mapperMatrix;
753 unitToPointsMatrix(transformPoints, &mapperMatrix);
754
755 SkMatrix finalMatrix = state.fCanvasTransform; 836 SkMatrix finalMatrix = state.fCanvasTransform;
756 finalMatrix.preConcat(state.fShaderTransform); 837 finalMatrix.preConcat(state.fShaderTransform);
757 finalMatrix.preConcat(mapperMatrix);
758 838
759 // Preserves as much as posible in the final matrix, and only removes 839 bool doStitchFunctions = (state.fType == SkShader::kLinear_GradientType ||
760 // the perspective. The inverse of the perspective is stored in 840 state.fType == SkShader::kRadial_GradientType ||
761 // perspectiveInverseOnly matrix and has 3 useful numbers 841 state.fType == SkShader::kConical_GradientType) &&
762 // (p0, p1, p2), while everything else is either 0 or 1. 842 info->fTileMode == SkShader::kClamp_TileMode &&
763 // In this way the shader will handle it eficiently, with minimal code. 843 !finalMatrix.hasPerspective();
764 SkMatrix perspectiveInverseOnly = SkMatrix::I();
765 if (finalMatrix.hasPerspective()) {
766 if (!split_perspective(finalMatrix,
767 &finalMatrix, &perspectiveInverseOnly)) {
768 return nullptr;
769 }
770 }
771
772 SkRect bbox;
773 bbox.set(state.fBBox);
774 if (!inverse_transform_bbox(finalMatrix, &bbox)) {
775 return nullptr;
776 }
777 844
778 auto domain = sk_make_sp<SkPDFArray>(); 845 auto domain = sk_make_sp<SkPDFArray>();
779 domain->reserve(4);
780 domain->appendScalar(bbox.fLeft);
781 domain->appendScalar(bbox.fRight);
782 domain->appendScalar(bbox.fTop);
783 domain->appendScalar(bbox.fBottom);
784 846
785 SkDynamicMemoryWStream functionCode; 847 int32_t shadingType = 1;
848 auto pdfShader = sk_make_sp<SkPDFDict>();
786 // The two point radial gradient further references 849 // The two point radial gradient further references
787 // state.fInfo 850 // state.fInfo
788 // in translating from x, y coordinates to the t parameter. So, we have 851 // in translating from x, y coordinates to the t parameter. So, we have
789 // to transform the points and radii according to the calculated matrix. 852 // to transform the points and radii according to the calculated matrix.
790 if (state.fType == SkShader::kConical_GradientType) { 853 if (doStitchFunctions) {
791 SkShader::GradientInfo twoPointRadialInfo = *info; 854 pdfShader->insertObject("Function", gradientStitchCode(*info));
792 SkMatrix inverseMapperMatrix; 855 shadingType = (state.fType == SkShader::kLinear_GradientType) ? 2 : 3;
793 if (!mapperMatrix.invert(&inverseMapperMatrix)) { 856
857 auto extend = sk_make_sp<SkPDFArray>();
858 extend->reserve(2);
859 extend->appendBool(true);
860 extend->appendBool(true);
861 pdfShader->insertObject("Extend", std::move(extend));
862
863 auto coords = sk_make_sp<SkPDFArray>();
864 if (state.fType == SkShader::kConical_GradientType) {
865 coords->reserve(6);
866 SkScalar r1 = info->fRadius[0];
867 SkScalar r2 = info->fRadius[1];
868 SkPoint pt1 = info->fPoint[0];
869 SkPoint pt2 = info->fPoint[1];
870 FixUpRadius(pt1, r1, pt2, r2);
871
872 coords->appendScalar(pt1.fX);
873 coords->appendScalar(pt1.fY);
874 coords->appendScalar(r1);
875
876 coords->appendScalar(pt2.fX);
877 coords->appendScalar(pt2.fY);
878 coords->appendScalar(r2);
879 } else if (state.fType == SkShader::kRadial_GradientType) {
880 coords->reserve(6);
881 const SkPoint& pt1 = info->fPoint[0];
882
883 coords->appendScalar(pt1.fX);
884 coords->appendScalar(pt1.fY);
885 coords->appendScalar(0);
886
887 coords->appendScalar(pt1.fX);
888 coords->appendScalar(pt1.fY);
889 coords->appendScalar(info->fRadius[0]);
890 } else {
891 coords->reserve(4);
892 const SkPoint& pt1 = info->fPoint[0];
893 const SkPoint& pt2 = info->fPoint[1];
894
895 coords->appendScalar(pt1.fX);
896 coords->appendScalar(pt1.fY);
897
898 coords->appendScalar(pt2.fX);
899 coords->appendScalar(pt2.fY);
900 }
901
902 pdfShader->insertObject("Coords", std::move(coords));
903 } else {
904 // Depending on the type of the gradient, we want to transform the
905 // coordinate space in different ways.
906 transformPoints[0] = info->fPoint[0];
907 transformPoints[1] = info->fPoint[1];
908 switch (state.fType) {
909 case SkShader::kLinear_GradientType:
910 codeFunction = &linearCode;
911 break;
912 case SkShader::kRadial_GradientType:
913 transformPoints[1] = transformPoints[0];
914 transformPoints[1].fX += info->fRadius[0];
915 codeFunction = &radialCode;
916 break;
917 case SkShader::kConical_GradientType: {
918 transformPoints[1] = transformPoints[0];
919 transformPoints[1].fX += SK_Scalar1;
920 codeFunction = &twoPointConicalCode;
921 break;
922 }
923 case SkShader::kSweep_GradientType:
924 transformPoints[1] = transformPoints[0];
925 transformPoints[1].fX += SK_Scalar1;
926 codeFunction = &sweepCode;
927 break;
928 case SkShader::kColor_GradientType:
929 case SkShader::kNone_GradientType:
930 default:
931 return nullptr;
932 }
933
934 // Move any scaling (assuming a unit gradient) or translation
935 // (and rotation for linear gradient), of the final gradient from
936 // info->fPoints to the matrix (updating bbox appropriately). Now
937 // the gradient can be drawn on on the unit segment.
938 SkMatrix mapperMatrix;
939 unitToPointsMatrix(transformPoints, &mapperMatrix);
940
941 finalMatrix.preConcat(mapperMatrix);
942
943 // Preserves as much as posible in the final matrix, and only removes
944 // the perspective. The inverse of the perspective is stored in
945 // perspectiveInverseOnly matrix and has 3 useful numbers
946 // (p0, p1, p2), while everything else is either 0 or 1.
947 // In this way the shader will handle it eficiently, with minimal code.
948 SkMatrix perspectiveInverseOnly = SkMatrix::I();
949 if (finalMatrix.hasPerspective()) {
950 if (!split_perspective(finalMatrix,
951 &finalMatrix, &perspectiveInverseOnly)) {
952 return nullptr;
953 }
954 }
955
956 SkRect bbox;
957 bbox.set(state.fBBox);
958 if (!inverse_transform_bbox(finalMatrix, &bbox)) {
794 return nullptr; 959 return nullptr;
795 } 960 }
796 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2); 961 domain->reserve(4);
797 twoPointRadialInfo.fRadius[0] = 962 domain->appendScalar(bbox.fLeft);
798 inverseMapperMatrix.mapRadius(info->fRadius[0]); 963 domain->appendScalar(bbox.fRight);
799 twoPointRadialInfo.fRadius[1] = 964 domain->appendScalar(bbox.fTop);
800 inverseMapperMatrix.mapRadius(info->fRadius[1]); 965 domain->appendScalar(bbox.fBottom);
801 codeFunction(twoPointRadialInfo, perspectiveInverseOnly, &functionCode); 966
802 } else { 967 SkDynamicMemoryWStream functionCode;
803 codeFunction(*info, perspectiveInverseOnly, &functionCode); 968
969 if (state.fType == SkShader::kConical_GradientType) {
970 SkShader::GradientInfo twoPointRadialInfo = *info;
971 SkMatrix inverseMapperMatrix;
972 if (!mapperMatrix.invert(&inverseMapperMatrix)) {
973 return nullptr;
974 }
975 inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2);
976 twoPointRadialInfo.fRadius[0] =
977 inverseMapperMatrix.mapRadius(info->fRadius[0]);
978 twoPointRadialInfo.fRadius[1] =
979 inverseMapperMatrix.mapRadius(info->fRadius[1]);
980 codeFunction(twoPointRadialInfo, perspectiveInverseOnly, &functionCo de);
981 } else {
982 codeFunction(*info, perspectiveInverseOnly, &functionCode);
983 }
984
985 pdfShader->insertObject("Domain", sk_ref_sp(domain.get()));
986
987 // Call canon->makeRangeObject() instead of
988 // SkPDFShader::MakeRangeObject() so that the canon can
989 // deduplicate.
990 std::unique_ptr<SkStreamAsset> functionStream(
991 functionCode.detachAsStream());
992 auto function = make_ps_function(std::move(functionStream), domain.get() ,
993 canon->makeRangeObject());
994 pdfShader->insertObjRef("Function", std::move(function));
804 } 995 }
805 996
806 auto pdfShader = sk_make_sp<SkPDFDict>(); 997 pdfShader->insertInt("ShadingType", shadingType);
807 pdfShader->insertInt("ShadingType", 1);
808 pdfShader->insertName("ColorSpace", "DeviceRGB"); 998 pdfShader->insertName("ColorSpace", "DeviceRGB");
809 pdfShader->insertObject("Domain", sk_ref_sp(domain.get()));
810
811 // Call canon->makeRangeObject() instead of
812 // SkPDFShader::MakeRangeObject() so that the canon can
813 // deduplicate.
814 std::unique_ptr<SkStreamAsset> functionStream(
815 functionCode.detachAsStream());
816 auto function = make_ps_function(std::move(functionStream), domain.get(),
817 canon->makeRangeObject());
818 pdfShader->insertObjRef("Function", std::move(function));
819 999
820 sk_sp<SkPDFFunctionShader> pdfFunctionShader( 1000 sk_sp<SkPDFFunctionShader> pdfFunctionShader(
821 new SkPDFFunctionShader(autoState->release())); 1001 new SkPDFFunctionShader(autoState->release()));
822 pdfFunctionShader->insertInt("PatternType", 2); 1002 pdfFunctionShader->insertInt("PatternType", 2);
823 pdfFunctionShader->insertObject("Matrix", 1003 pdfFunctionShader->insertObject("Matrix",
824 SkPDFUtils::MatrixToArray(finalMatrix)); 1004 SkPDFUtils::MatrixToArray(finalMatrix));
825 pdfFunctionShader->insertObject("Shading", std::move(pdfShader)); 1005 pdfFunctionShader->insertObject("Shading", std::move(pdfShader));
826 1006
827 canon->addFunctionShader(pdfFunctionShader.get()); 1007 canon->addFunctionShader(pdfFunctionShader.get());
828 return pdfFunctionShader.release(); 1008 return pdfFunctionShader.release();
(...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after
1231 return false; 1411 return false;
1232 } 1412 }
1233 1413
1234 void SkPDFShader::State::AllocateGradientInfoStorage() { 1414 void SkPDFShader::State::AllocateGradientInfoStorage() {
1235 fColorData.set(sk_malloc_throw( 1415 fColorData.set(sk_malloc_throw(
1236 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar)))); 1416 fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar))));
1237 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get()); 1417 fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get());
1238 fInfo.fColorOffsets = 1418 fInfo.fColorOffsets =
1239 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount); 1419 reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount);
1240 } 1420 }
OLDNEW
« no previous file with comments | « AUTHORS ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698