1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #include "SkPDFShader.h"
11 
12 #include "SkData.h"
13 #include "SkOncePtr.h"
14 #include "SkPDFCanon.h"
15 #include "SkPDFDevice.h"
16 #include "SkPDFFormXObject.h"
17 #include "SkPDFGraphicState.h"
18 #include "SkPDFResourceDict.h"
19 #include "SkPDFUtils.h"
20 #include "SkScalar.h"
21 #include "SkStream.h"
22 #include "SkTemplates.h"
23 #include "SkTypes.h"
24 
inverse_transform_bbox(const SkMatrix & matrix,SkRect * bbox)25 static bool inverse_transform_bbox(const SkMatrix& matrix, SkRect* bbox) {
26     SkMatrix inverse;
27     if (!matrix.invert(&inverse)) {
28         return false;
29     }
30     inverse.mapRect(bbox);
31     return true;
32 }
33 
unitToPointsMatrix(const SkPoint pts[2],SkMatrix * matrix)34 static void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) {
35     SkVector    vec = pts[1] - pts[0];
36     SkScalar    mag = vec.length();
37     SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
38 
39     vec.scale(inv);
40     matrix->setSinCos(vec.fY, vec.fX);
41     matrix->preScale(mag, mag);
42     matrix->postTranslate(pts[0].fX, pts[0].fY);
43 }
44 
45 /* Assumes t + startOffset is on the stack and does a linear interpolation on t
46    between startOffset and endOffset from prevColor to curColor (for each color
47    component), leaving the result in component order on the stack. It assumes
48    there are always 3 components per color.
49    @param range                  endOffset - startOffset
50    @param curColor[components]   The current color components.
51    @param prevColor[components]  The previous color components.
52    @param result                 The result ps function.
53  */
interpolateColorCode(SkScalar range,SkScalar * curColor,SkScalar * prevColor,SkString * result)54 static void interpolateColorCode(SkScalar range, SkScalar* curColor,
55                                  SkScalar* prevColor, SkString* result) {
56     SkASSERT(range != SkIntToScalar(0));
57     static const int kColorComponents = 3;
58 
59     // Figure out how to scale each color component.
60     SkScalar multiplier[kColorComponents];
61     for (int i = 0; i < kColorComponents; i++) {
62         multiplier[i] = (curColor[i] - prevColor[i]) / range;
63     }
64 
65     // Calculate when we no longer need to keep a copy of the input parameter t.
66     // If the last component to use t is i, then dupInput[0..i - 1] = true
67     // and dupInput[i .. components] = false.
68     bool dupInput[kColorComponents];
69     dupInput[kColorComponents - 1] = false;
70     for (int i = kColorComponents - 2; i >= 0; i--) {
71         dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0;
72     }
73 
74     if (!dupInput[0] && multiplier[0] == 0) {
75         result->append("pop ");
76     }
77 
78     for (int i = 0; i < kColorComponents; i++) {
79         // If the next components needs t and this component will consume a
80         // copy, make another copy.
81         if (dupInput[i] && multiplier[i] != 0) {
82             result->append("dup ");
83         }
84 
85         if (multiplier[i] == 0) {
86             result->appendScalar(prevColor[i]);
87             result->append(" ");
88         } else {
89             if (multiplier[i] != 1) {
90                 result->appendScalar(multiplier[i]);
91                 result->append(" mul ");
92             }
93             if (prevColor[i] != 0) {
94                 result->appendScalar(prevColor[i]);
95                 result->append(" add ");
96             }
97         }
98 
99         if (dupInput[i]) {
100             result->append("exch\n");
101         }
102     }
103 }
104 
105 /* Generate Type 4 function code to map t=[0,1) to the passed gradient,
106    clamping at the edges of the range.  The generated code will be of the form:
107        if (t < 0) {
108            return colorData[0][r,g,b];
109        } else {
110            if (t < info.fColorOffsets[1]) {
111                return linearinterpolation(colorData[0][r,g,b],
112                                           colorData[1][r,g,b]);
113            } else {
114                if (t < info.fColorOffsets[2]) {
115                    return linearinterpolation(colorData[1][r,g,b],
116                                               colorData[2][r,g,b]);
117                } else {
118 
119                 ...    } else {
120                            return colorData[info.fColorCount - 1][r,g,b];
121                        }
122                 ...
123            }
124        }
125  */
gradientFunctionCode(const SkShader::GradientInfo & info,SkString * result)126 static void gradientFunctionCode(const SkShader::GradientInfo& info,
127                                  SkString* result) {
128     /* We want to linearly interpolate from the previous color to the next.
129        Scale the colors from 0..255 to 0..1 and determine the multipliers
130        for interpolation.
131        C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}.
132      */
133     static const int kColorComponents = 3;
134     typedef SkScalar ColorTuple[kColorComponents];
135     SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount);
136     ColorTuple *colorData = colorDataAlloc.get();
137     const SkScalar scale = SkScalarInvert(SkIntToScalar(255));
138     for (int i = 0; i < info.fColorCount; i++) {
139         colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale);
140         colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale);
141         colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale);
142     }
143 
144     // Clamp the initial color.
145     result->append("dup 0 le {pop ");
146     result->appendScalar(colorData[0][0]);
147     result->append(" ");
148     result->appendScalar(colorData[0][1]);
149     result->append(" ");
150     result->appendScalar(colorData[0][2]);
151     result->append(" }\n");
152 
153     // The gradient colors.
154     int gradients = 0;
155     for (int i = 1 ; i < info.fColorCount; i++) {
156         if (info.fColorOffsets[i] == info.fColorOffsets[i - 1]) {
157             continue;
158         }
159         gradients++;
160 
161         result->append("{dup ");
162         result->appendScalar(info.fColorOffsets[i]);
163         result->append(" le {");
164         if (info.fColorOffsets[i - 1] != 0) {
165             result->appendScalar(info.fColorOffsets[i - 1]);
166             result->append(" sub\n");
167         }
168 
169         interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1],
170                              colorData[i], colorData[i - 1], result);
171         result->append("}\n");
172     }
173 
174     // Clamp the final color.
175     result->append("{pop ");
176     result->appendScalar(colorData[info.fColorCount - 1][0]);
177     result->append(" ");
178     result->appendScalar(colorData[info.fColorCount - 1][1]);
179     result->append(" ");
180     result->appendScalar(colorData[info.fColorCount - 1][2]);
181 
182     for (int i = 0 ; i < gradients + 1; i++) {
183         result->append("} ifelse\n");
184     }
185 }
186 
187 /* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */
tileModeCode(SkShader::TileMode mode,SkString * result)188 static void tileModeCode(SkShader::TileMode mode, SkString* result) {
189     if (mode == SkShader::kRepeat_TileMode) {
190         result->append("dup truncate sub\n");  // Get the fractional part.
191         result->append("dup 0 le {1 add} if\n");  // Map (-1,0) => (0,1)
192         return;
193     }
194 
195     if (mode == SkShader::kMirror_TileMode) {
196         // Map t mod 2 into [0, 1, 1, 0].
197         //               Code                     Stack
198         result->append("abs "                 // Map negative to positive.
199                        "dup "                 // t.s t.s
200                        "truncate "            // t.s t
201                        "dup "                 // t.s t t
202                        "cvi "                 // t.s t T
203                        "2 mod "               // t.s t (i mod 2)
204                        "1 eq "                // t.s t true|false
205                        "3 1 roll "            // true|false t.s t
206                        "sub "                 // true|false 0.s
207                        "exch "                // 0.s true|false
208                        "{1 exch sub} if\n");  // 1 - 0.s|0.s
209     }
210 }
211 
212 /**
213  *  Returns PS function code that applies inverse perspective
214  *  to a x, y point.
215  *  The function assumes that the stack has at least two elements,
216  *  and that the top 2 elements are numeric values.
217  *  After executing this code on a PS stack, the last 2 elements are updated
218  *  while the rest of the stack is preserved intact.
219  *  inversePerspectiveMatrix is the inverse perspective matrix.
220  */
apply_perspective_to_coordinates(const SkMatrix & inversePerspectiveMatrix)221 static SkString apply_perspective_to_coordinates(
222         const SkMatrix& inversePerspectiveMatrix) {
223     SkString code;
224     if (!inversePerspectiveMatrix.hasPerspective()) {
225         return code;
226     }
227 
228     // Perspective matrix should be:
229     // 1   0  0
230     // 0   1  0
231     // p0 p1 p2
232 
233     const SkScalar p0 = inversePerspectiveMatrix[SkMatrix::kMPersp0];
234     const SkScalar p1 = inversePerspectiveMatrix[SkMatrix::kMPersp1];
235     const SkScalar p2 = inversePerspectiveMatrix[SkMatrix::kMPersp2];
236 
237     // y = y / (p2 + p0 x + p1 y)
238     // x = x / (p2 + p0 x + p1 y)
239 
240     // Input on stack: x y
241     code.append(" dup ");               // x y y
242     code.appendScalar(p1);              // x y y p1
243     code.append(" mul "                 // x y y*p1
244                 " 2 index ");           // x y y*p1 x
245     code.appendScalar(p0);              // x y y p1 x p0
246     code.append(" mul ");               // x y y*p1 x*p0
247     code.appendScalar(p2);              // x y y p1 x*p0 p2
248     code.append(" add "                 // x y y*p1 x*p0+p2
249                 "add "                  // x y y*p1+x*p0+p2
250                 "3 1 roll "             // y*p1+x*p0+p2 x y
251                 "2 index "              // z x y y*p1+x*p0+p2
252                 "div "                  // y*p1+x*p0+p2 x y/(y*p1+x*p0+p2)
253                 "3 1 roll "             // y/(y*p1+x*p0+p2) y*p1+x*p0+p2 x
254                 "exch "                 // y/(y*p1+x*p0+p2) x y*p1+x*p0+p2
255                 "div "                  // y/(y*p1+x*p0+p2) x/(y*p1+x*p0+p2)
256                 "exch\n");              // x/(y*p1+x*p0+p2) y/(y*p1+x*p0+p2)
257     return code;
258 }
259 
linearCode(const SkShader::GradientInfo & info,const SkMatrix & perspectiveRemover)260 static SkString linearCode(const SkShader::GradientInfo& info,
261                            const SkMatrix& perspectiveRemover) {
262     SkString function("{");
263 
264     function.append(apply_perspective_to_coordinates(perspectiveRemover));
265 
266     function.append("pop\n");  // Just ditch the y value.
267     tileModeCode(info.fTileMode, &function);
268     gradientFunctionCode(info, &function);
269     function.append("}");
270     return function;
271 }
272 
radialCode(const SkShader::GradientInfo & info,const SkMatrix & perspectiveRemover)273 static SkString radialCode(const SkShader::GradientInfo& info,
274                            const SkMatrix& perspectiveRemover) {
275     SkString function("{");
276 
277     function.append(apply_perspective_to_coordinates(perspectiveRemover));
278 
279     // Find the distance from the origin.
280     function.append("dup "      // x y y
281                     "mul "      // x y^2
282                     "exch "     // y^2 x
283                     "dup "      // y^2 x x
284                     "mul "      // y^2 x^2
285                     "add "      // y^2+x^2
286                     "sqrt\n");  // sqrt(y^2+x^2)
287 
288     tileModeCode(info.fTileMode, &function);
289     gradientFunctionCode(info, &function);
290     function.append("}");
291     return function;
292 }
293 
294 /* Conical gradient shader, based on the Canvas spec for radial gradients
295    See: http://www.w3.org/TR/2dcontext/#dom-context-2d-createradialgradient
296  */
twoPointConicalCode(const SkShader::GradientInfo & info,const SkMatrix & perspectiveRemover)297 static SkString twoPointConicalCode(const SkShader::GradientInfo& info,
298                                     const SkMatrix& perspectiveRemover) {
299     SkScalar dx = info.fPoint[1].fX - info.fPoint[0].fX;
300     SkScalar dy = info.fPoint[1].fY - info.fPoint[0].fY;
301     SkScalar r0 = info.fRadius[0];
302     SkScalar dr = info.fRadius[1] - info.fRadius[0];
303     SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) -
304                  SkScalarMul(dr, dr);
305 
306     // First compute t, if the pixel falls outside the cone, then we'll end
307     // with 'false' on the stack, otherwise we'll push 'true' with t below it
308 
309     // We start with a stack of (x y), copy it and then consume one copy in
310     // order to calculate b and the other to calculate c.
311     SkString function("{");
312 
313     function.append(apply_perspective_to_coordinates(perspectiveRemover));
314 
315     function.append("2 copy ");
316 
317     // Calculate b and b^2; b = -2 * (y * dy + x * dx + r0 * dr).
318     function.appendScalar(dy);
319     function.append(" mul exch ");
320     function.appendScalar(dx);
321     function.append(" mul add ");
322     function.appendScalar(SkScalarMul(r0, dr));
323     function.append(" add -2 mul dup dup mul\n");
324 
325     // c = x^2 + y^2 + radius0^2
326     function.append("4 2 roll dup mul exch dup mul add ");
327     function.appendScalar(SkScalarMul(r0, r0));
328     function.append(" sub dup 4 1 roll\n");
329 
330     // Contents of the stack at this point: c, b, b^2, c
331 
332     // if a = 0, then we collapse to a simpler linear case
333     if (a == 0) {
334 
335         // t = -c/b
336         function.append("pop pop div neg dup ");
337 
338         // compute radius(t)
339         function.appendScalar(dr);
340         function.append(" mul ");
341         function.appendScalar(r0);
342         function.append(" add\n");
343 
344         // if r(t) < 0, then it's outside the cone
345         function.append("0 lt {pop false} {true} ifelse\n");
346 
347     } else {
348 
349         // quadratic case: the Canvas spec wants the largest
350         // root t for which radius(t) > 0
351 
352         // compute the discriminant (b^2 - 4ac)
353         function.appendScalar(SkScalarMul(SkIntToScalar(4), a));
354         function.append(" mul sub dup\n");
355 
356         // if d >= 0, proceed
357         function.append("0 ge {\n");
358 
359         // an intermediate value we'll use to compute the roots:
360         // q = -0.5 * (b +/- sqrt(d))
361         function.append("sqrt exch dup 0 lt {exch -1 mul} if");
362         function.append(" add -0.5 mul dup\n");
363 
364         // first root = q / a
365         function.appendScalar(a);
366         function.append(" div\n");
367 
368         // second root = c / q
369         function.append("3 1 roll div\n");
370 
371         // put the larger root on top of the stack
372         function.append("2 copy gt {exch} if\n");
373 
374         // compute radius(t) for larger root
375         function.append("dup ");
376         function.appendScalar(dr);
377         function.append(" mul ");
378         function.appendScalar(r0);
379         function.append(" add\n");
380 
381         // if r(t) > 0, we have our t, pop off the smaller root and we're done
382         function.append(" 0 gt {exch pop true}\n");
383 
384         // otherwise, throw out the larger one and try the smaller root
385         function.append("{pop dup\n");
386         function.appendScalar(dr);
387         function.append(" mul ");
388         function.appendScalar(r0);
389         function.append(" add\n");
390 
391         // if r(t) < 0, push false, otherwise the smaller root is our t
392         function.append("0 le {pop false} {true} ifelse\n");
393         function.append("} ifelse\n");
394 
395         // d < 0, clear the stack and push false
396         function.append("} {pop pop pop false} ifelse\n");
397     }
398 
399     // if the pixel is in the cone, proceed to compute a color
400     function.append("{");
401     tileModeCode(info.fTileMode, &function);
402     gradientFunctionCode(info, &function);
403 
404     // otherwise, just write black
405     function.append("} {0 0 0} ifelse }");
406 
407     return function;
408 }
409 
sweepCode(const SkShader::GradientInfo & info,const SkMatrix & perspectiveRemover)410 static SkString sweepCode(const SkShader::GradientInfo& info,
411                           const SkMatrix& perspectiveRemover) {
412     SkString function("{exch atan 360 div\n");
413     tileModeCode(info.fTileMode, &function);
414     gradientFunctionCode(info, &function);
415     function.append("}");
416     return function;
417 }
418 
drawBitmapMatrix(SkCanvas * canvas,const SkBitmap & bm,const SkMatrix & matrix)419 static void drawBitmapMatrix(SkCanvas* canvas, const SkBitmap& bm, const SkMatrix& matrix) {
420     SkAutoCanvasRestore acr(canvas, true);
421     canvas->concat(matrix);
422     canvas->drawBitmap(bm, 0, 0);
423 }
424 
425 class SkPDFShader::State {
426 public:
427     SkShader::GradientType fType;
428     SkShader::GradientInfo fInfo;
429     SkAutoFree fColorData;    // This provides storage for arrays in fInfo.
430     SkMatrix fCanvasTransform;
431     SkMatrix fShaderTransform;
432     SkIRect fBBox;
433 
434     SkBitmap fImage;
435     uint32_t fPixelGeneration;
436     SkShader::TileMode fImageTileModes[2];
437 
438     State(const SkShader& shader, const SkMatrix& canvasTransform,
439           const SkIRect& bbox, SkScalar rasterScale);
440 
441     bool operator==(const State& b) const;
442 
443     SkPDFShader::State* CreateAlphaToLuminosityState() const;
444     SkPDFShader::State* CreateOpaqueState() const;
445 
446     bool GradientHasAlpha() const;
447 
448 private:
449     State(const State& other);
450     State operator=(const State& rhs);
451     void AllocateGradientInfoStorage();
452 };
453 
454 ////////////////////////////////////////////////////////////////////////////////
455 
SkPDFFunctionShader(SkPDFShader::State * state)456 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
457     : SkPDFDict("Pattern"), fShaderState(state) {}
458 
~SkPDFFunctionShader()459 SkPDFFunctionShader::~SkPDFFunctionShader() {}
460 
equals(const SkPDFShader::State & state) const461 bool SkPDFFunctionShader::equals(const SkPDFShader::State& state) const {
462     return state == *fShaderState;
463 }
464 
465 ////////////////////////////////////////////////////////////////////////////////
466 
SkPDFAlphaFunctionShader(SkPDFShader::State * state)467 SkPDFAlphaFunctionShader::SkPDFAlphaFunctionShader(SkPDFShader::State* state)
468     : fShaderState(state) {}
469 
equals(const SkPDFShader::State & state) const470 bool SkPDFAlphaFunctionShader::equals(const SkPDFShader::State& state) const {
471     return state == *fShaderState;
472 }
473 
~SkPDFAlphaFunctionShader()474 SkPDFAlphaFunctionShader::~SkPDFAlphaFunctionShader() {}
475 
476 ////////////////////////////////////////////////////////////////////////////////
477 
SkPDFImageShader(SkPDFShader::State * state)478 SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state)
479     : fShaderState(state) {}
480 
equals(const SkPDFShader::State & state) const481 bool SkPDFImageShader::equals(const SkPDFShader::State& state) const {
482     return state == *fShaderState;
483 }
484 
~SkPDFImageShader()485 SkPDFImageShader::~SkPDFImageShader() {}
486 
487 ////////////////////////////////////////////////////////////////////////////////
488 
get_pdf_shader_by_state(SkPDFCanon * canon,SkScalar dpi,SkAutoTDelete<SkPDFShader::State> * autoState)489 static SkPDFObject* get_pdf_shader_by_state(
490         SkPDFCanon* canon,
491         SkScalar dpi,
492         SkAutoTDelete<SkPDFShader::State>* autoState) {
493     const SkPDFShader::State& state = **autoState;
494     if (state.fType == SkShader::kNone_GradientType && state.fImage.isNull()) {
495         // TODO(vandebo) This drops SKComposeShader on the floor.  We could
496         // handle compose shader by pulling things up to a layer, drawing with
497         // the first shader, applying the xfer mode and drawing again with the
498         // second shader, then applying the layer to the original drawing.
499         return nullptr;
500     } else if (state.fType == SkShader::kNone_GradientType) {
501         SkPDFObject* shader = canon->findImageShader(state);
502         return shader ? SkRef(shader)
503                       : SkPDFImageShader::Create(canon, dpi, autoState);
504     } else if (state.GradientHasAlpha()) {
505         SkPDFObject* shader = canon->findAlphaShader(state);
506         return shader ? SkRef(shader)
507                       : SkPDFAlphaFunctionShader::Create(canon, dpi, autoState);
508     } else {
509         SkPDFObject* shader = canon->findFunctionShader(state);
510         return shader ? SkRef(shader)
511                       : SkPDFFunctionShader::Create(canon, autoState);
512     }
513 }
514 
515 // static
GetPDFShader(SkPDFCanon * canon,SkScalar dpi,const SkShader & shader,const SkMatrix & matrix,const SkIRect & surfaceBBox,SkScalar rasterScale)516 SkPDFObject* SkPDFShader::GetPDFShader(SkPDFCanon* canon,
517                                        SkScalar dpi,
518                                        const SkShader& shader,
519                                        const SkMatrix& matrix,
520                                        const SkIRect& surfaceBBox,
521                                        SkScalar rasterScale) {
522     SkAutoTDelete<SkPDFShader::State> state(new State(shader, matrix, surfaceBBox, rasterScale));
523     return get_pdf_shader_by_state(canon, dpi, &state);
524 }
525 
get_gradient_resource_dict(SkPDFObject * functionShader,SkPDFObject * gState)526 static SkPDFDict* get_gradient_resource_dict(
527         SkPDFObject* functionShader,
528         SkPDFObject* gState) {
529     SkTDArray<SkPDFObject*> patterns;
530     if (functionShader) {
531         patterns.push(functionShader);
532     }
533     SkTDArray<SkPDFObject*> graphicStates;
534     if (gState) {
535         graphicStates.push(gState);
536     }
537     return SkPDFResourceDict::Create(&graphicStates, &patterns, nullptr, nullptr);
538 }
539 
populate_tiling_pattern_dict(SkPDFDict * pattern,SkRect & bbox,SkPDFDict * resources,const SkMatrix & matrix)540 static void populate_tiling_pattern_dict(SkPDFDict* pattern,
541                                          SkRect& bbox,
542                                          SkPDFDict* resources,
543                                          const SkMatrix& matrix) {
544     const int kTiling_PatternType = 1;
545     const int kColoredTilingPattern_PaintType = 1;
546     const int kConstantSpacing_TilingType = 1;
547 
548     pattern->insertName("Type", "Pattern");
549     pattern->insertInt("PatternType", kTiling_PatternType);
550     pattern->insertInt("PaintType", kColoredTilingPattern_PaintType);
551     pattern->insertInt("TilingType", kConstantSpacing_TilingType);
552     pattern->insertObject("BBox", SkPDFUtils::RectToArray(bbox));
553     pattern->insertScalar("XStep", bbox.width());
554     pattern->insertScalar("YStep", bbox.height());
555     pattern->insertObject("Resources", SkRef(resources));
556     if (!matrix.isIdentity()) {
557         pattern->insertObject("Matrix", SkPDFUtils::MatrixToArray(matrix));
558     }
559 }
560 
561 /**
562  * Creates a content stream which fills the pattern P0 across bounds.
563  * @param gsIndex A graphics state resource index to apply, or <0 if no
564  * graphics state to apply.
565  */
create_pattern_fill_content(int gsIndex,SkRect & bounds)566 static SkStream* create_pattern_fill_content(int gsIndex, SkRect& bounds) {
567     SkDynamicMemoryWStream content;
568     if (gsIndex >= 0) {
569         SkPDFUtils::ApplyGraphicState(gsIndex, &content);
570     }
571     SkPDFUtils::ApplyPattern(0, &content);
572     SkPDFUtils::AppendRectangle(bounds, &content);
573     SkPDFUtils::PaintPath(SkPaint::kFill_Style, SkPath::kEvenOdd_FillType,
574                           &content);
575 
576     return content.detachAsStream();
577 }
578 
579 /**
580  * Creates a ExtGState with the SMask set to the luminosityShader in
581  * luminosity mode. The shader pattern extends to the bbox.
582  */
create_smask_graphic_state(SkPDFCanon * canon,SkScalar dpi,const SkPDFShader::State & state)583 static SkPDFObject* create_smask_graphic_state(
584         SkPDFCanon* canon, SkScalar dpi, const SkPDFShader::State& state) {
585     SkRect bbox;
586     bbox.set(state.fBBox);
587 
588     SkAutoTDelete<SkPDFShader::State> alphaToLuminosityState(
589             state.CreateAlphaToLuminosityState());
590     SkAutoTUnref<SkPDFObject> luminosityShader(
591             get_pdf_shader_by_state(canon, dpi, &alphaToLuminosityState));
592 
593     SkAutoTDelete<SkStream> alphaStream(create_pattern_fill_content(-1, bbox));
594 
595     SkAutoTUnref<SkPDFDict>
596         resources(get_gradient_resource_dict(luminosityShader, nullptr));
597 
598     SkAutoTUnref<SkPDFFormXObject> alphaMask(
599             new SkPDFFormXObject(alphaStream.get(), bbox, resources.get()));
600 
601     return SkPDFGraphicState::GetSMaskGraphicState(
602             alphaMask.get(), false,
603             SkPDFGraphicState::kLuminosity_SMaskMode);
604 }
605 
Create(SkPDFCanon * canon,SkScalar dpi,SkAutoTDelete<SkPDFShader::State> * autoState)606 SkPDFAlphaFunctionShader* SkPDFAlphaFunctionShader::Create(
607         SkPDFCanon* canon,
608         SkScalar dpi,
609         SkAutoTDelete<SkPDFShader::State>* autoState) {
610     const SkPDFShader::State& state = **autoState;
611     SkRect bbox;
612     bbox.set(state.fBBox);
613 
614     SkAutoTDelete<SkPDFShader::State> opaqueState(state.CreateOpaqueState());
615 
616     SkAutoTUnref<SkPDFObject> colorShader(
617             get_pdf_shader_by_state(canon, dpi, &opaqueState));
618     if (!colorShader) {
619         return nullptr;
620     }
621 
622     // Create resource dict with alpha graphics state as G0 and
623     // pattern shader as P0, then write content stream.
624     SkAutoTUnref<SkPDFObject> alphaGs(
625             create_smask_graphic_state(canon, dpi, state));
626 
627     SkPDFAlphaFunctionShader* alphaFunctionShader =
628             new SkPDFAlphaFunctionShader(autoState->detach());
629 
630     SkAutoTUnref<SkPDFDict> resourceDict(
631             get_gradient_resource_dict(colorShader.get(), alphaGs.get()));
632 
633     SkAutoTDelete<SkStream> colorStream(
634             create_pattern_fill_content(0, bbox));
635     alphaFunctionShader->setData(colorStream.get());
636 
637     populate_tiling_pattern_dict(alphaFunctionShader, bbox, resourceDict.get(),
638                                  SkMatrix::I());
639     canon->addAlphaShader(alphaFunctionShader);
640     return alphaFunctionShader;
641 }
642 
643 // Finds affine and persp such that in = affine * persp.
644 // but it returns the inverse of perspective matrix.
split_perspective(const SkMatrix in,SkMatrix * affine,SkMatrix * perspectiveInverse)645 static bool split_perspective(const SkMatrix in, SkMatrix* affine,
646                               SkMatrix* perspectiveInverse) {
647     const SkScalar p2 = in[SkMatrix::kMPersp2];
648 
649     if (SkScalarNearlyZero(p2)) {
650         return false;
651     }
652 
653     const SkScalar zero = SkIntToScalar(0);
654     const SkScalar one = SkIntToScalar(1);
655 
656     const SkScalar sx = in[SkMatrix::kMScaleX];
657     const SkScalar kx = in[SkMatrix::kMSkewX];
658     const SkScalar tx = in[SkMatrix::kMTransX];
659     const SkScalar ky = in[SkMatrix::kMSkewY];
660     const SkScalar sy = in[SkMatrix::kMScaleY];
661     const SkScalar ty = in[SkMatrix::kMTransY];
662     const SkScalar p0 = in[SkMatrix::kMPersp0];
663     const SkScalar p1 = in[SkMatrix::kMPersp1];
664 
665     // Perspective matrix would be:
666     // 1  0  0
667     // 0  1  0
668     // p0 p1 p2
669     // But we need the inverse of persp.
670     perspectiveInverse->setAll(one,          zero,       zero,
671                                zero,         one,        zero,
672                                -p0/p2,     -p1/p2,     1/p2);
673 
674     affine->setAll(sx - p0 * tx / p2,       kx - p1 * tx / p2,      tx / p2,
675                    ky - p0 * ty / p2,       sy - p1 * ty / p2,      ty / p2,
676                    zero,                    zero,                   one);
677 
678     return true;
679 }
680 
create_range_object()681 static SkPDFObject* create_range_object() {
682     SkPDFArray* range = new SkPDFArray;
683     range->reserve(6);
684     range->appendInt(0);
685     range->appendInt(1);
686     range->appendInt(0);
687     range->appendInt(1);
688     range->appendInt(0);
689     range->appendInt(1);
690     return range;
691 }
692 SK_DECLARE_STATIC_ONCE_PTR(SkPDFObject, rangeObject);
693 
make_ps_function(const SkString & psCode,SkPDFArray * domain)694 static SkPDFStream* make_ps_function(const SkString& psCode,
695                                      SkPDFArray* domain) {
696     SkAutoDataUnref funcData(
697             SkData::NewWithCopy(psCode.c_str(), psCode.size()));
698     SkPDFStream* result = new SkPDFStream(funcData.get());
699     result->insertInt("FunctionType", 4);
700     result->insertObject("Domain", SkRef(domain));
701     result->insertObject("Range", SkRef(rangeObject.get(create_range_object)));
702     return result;
703 }
704 
Create(SkPDFCanon * canon,SkAutoTDelete<SkPDFShader::State> * autoState)705 SkPDFFunctionShader* SkPDFFunctionShader::Create(
706         SkPDFCanon* canon, SkAutoTDelete<SkPDFShader::State>* autoState) {
707     const SkPDFShader::State& state = **autoState;
708 
709     SkString (*codeFunction)(const SkShader::GradientInfo& info,
710                              const SkMatrix& perspectiveRemover) = nullptr;
711     SkPoint transformPoints[2];
712 
713     // Depending on the type of the gradient, we want to transform the
714     // coordinate space in different ways.
715     const SkShader::GradientInfo* info = &state.fInfo;
716     transformPoints[0] = info->fPoint[0];
717     transformPoints[1] = info->fPoint[1];
718     switch (state.fType) {
719         case SkShader::kLinear_GradientType:
720             codeFunction = &linearCode;
721             break;
722         case SkShader::kRadial_GradientType:
723             transformPoints[1] = transformPoints[0];
724             transformPoints[1].fX += info->fRadius[0];
725             codeFunction = &radialCode;
726             break;
727         case SkShader::kConical_GradientType: {
728             transformPoints[1] = transformPoints[0];
729             transformPoints[1].fX += SK_Scalar1;
730             codeFunction = &twoPointConicalCode;
731             break;
732         }
733         case SkShader::kSweep_GradientType:
734             transformPoints[1] = transformPoints[0];
735             transformPoints[1].fX += SK_Scalar1;
736             codeFunction = &sweepCode;
737             break;
738         case SkShader::kColor_GradientType:
739         case SkShader::kNone_GradientType:
740         default:
741             return nullptr;
742     }
743 
744     // Move any scaling (assuming a unit gradient) or translation
745     // (and rotation for linear gradient), of the final gradient from
746     // info->fPoints to the matrix (updating bbox appropriately).  Now
747     // the gradient can be drawn on on the unit segment.
748     SkMatrix mapperMatrix;
749     unitToPointsMatrix(transformPoints, &mapperMatrix);
750 
751     SkMatrix finalMatrix = state.fCanvasTransform;
752     finalMatrix.preConcat(state.fShaderTransform);
753     finalMatrix.preConcat(mapperMatrix);
754 
755     // Preserves as much as posible in the final matrix, and only removes
756     // the perspective. The inverse of the perspective is stored in
757     // perspectiveInverseOnly matrix and has 3 useful numbers
758     // (p0, p1, p2), while everything else is either 0 or 1.
759     // In this way the shader will handle it eficiently, with minimal code.
760     SkMatrix perspectiveInverseOnly = SkMatrix::I();
761     if (finalMatrix.hasPerspective()) {
762         if (!split_perspective(finalMatrix,
763                                &finalMatrix, &perspectiveInverseOnly)) {
764             return nullptr;
765         }
766     }
767 
768     SkRect bbox;
769     bbox.set(state.fBBox);
770     if (!inverse_transform_bbox(finalMatrix, &bbox)) {
771         return nullptr;
772     }
773 
774     SkAutoTUnref<SkPDFArray> domain(new SkPDFArray);
775     domain->reserve(4);
776     domain->appendScalar(bbox.fLeft);
777     domain->appendScalar(bbox.fRight);
778     domain->appendScalar(bbox.fTop);
779     domain->appendScalar(bbox.fBottom);
780 
781     SkString functionCode;
782     // The two point radial gradient further references
783     // state.fInfo
784     // in translating from x, y coordinates to the t parameter. So, we have
785     // to transform the points and radii according to the calculated matrix.
786     if (state.fType == SkShader::kConical_GradientType) {
787         SkShader::GradientInfo twoPointRadialInfo = *info;
788         SkMatrix inverseMapperMatrix;
789         if (!mapperMatrix.invert(&inverseMapperMatrix)) {
790             return nullptr;
791         }
792         inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2);
793         twoPointRadialInfo.fRadius[0] =
794             inverseMapperMatrix.mapRadius(info->fRadius[0]);
795         twoPointRadialInfo.fRadius[1] =
796             inverseMapperMatrix.mapRadius(info->fRadius[1]);
797         functionCode = codeFunction(twoPointRadialInfo, perspectiveInverseOnly);
798     } else {
799         functionCode = codeFunction(*info, perspectiveInverseOnly);
800     }
801 
802     SkAutoTUnref<SkPDFDict> pdfShader(new SkPDFDict);
803     pdfShader->insertInt("ShadingType", 1);
804     pdfShader->insertName("ColorSpace", "DeviceRGB");
805     pdfShader->insertObject("Domain", SkRef(domain.get()));
806 
807     SkAutoTUnref<SkPDFStream> function(
808             make_ps_function(functionCode, domain.get()));
809     pdfShader->insertObjRef("Function", function.detach());
810 
811     SkPDFFunctionShader* pdfFunctionShader = new SkPDFFunctionShader(autoState->detach());
812 
813     pdfFunctionShader->insertInt("PatternType", 2);
814     pdfFunctionShader->insertObject("Matrix",
815                                     SkPDFUtils::MatrixToArray(finalMatrix));
816     pdfFunctionShader->insertObject("Shading", pdfShader.detach());
817 
818     canon->addFunctionShader(pdfFunctionShader);
819     return pdfFunctionShader;
820 }
821 
Create(SkPDFCanon * canon,SkScalar dpi,SkAutoTDelete<SkPDFShader::State> * autoState)822 SkPDFImageShader* SkPDFImageShader::Create(
823         SkPDFCanon* canon,
824         SkScalar dpi,
825         SkAutoTDelete<SkPDFShader::State>* autoState) {
826     const SkPDFShader::State& state = **autoState;
827 
828     state.fImage.lockPixels();
829 
830     // The image shader pattern cell will be drawn into a separate device
831     // in pattern cell space (no scaling on the bitmap, though there may be
832     // translations so that all content is in the device, coordinates > 0).
833 
834     // Map clip bounds to shader space to ensure the device is large enough
835     // to handle fake clamping.
836     SkMatrix finalMatrix = state.fCanvasTransform;
837     finalMatrix.preConcat(state.fShaderTransform);
838     SkRect deviceBounds;
839     deviceBounds.set(state.fBBox);
840     if (!inverse_transform_bbox(finalMatrix, &deviceBounds)) {
841         return nullptr;
842     }
843 
844     const SkBitmap* image = &state.fImage;
845     SkRect bitmapBounds;
846     image->getBounds(&bitmapBounds);
847 
848     // For tiling modes, the bounds should be extended to include the bitmap,
849     // otherwise the bitmap gets clipped out and the shader is empty and awful.
850     // For clamp modes, we're only interested in the clip region, whether
851     // or not the main bitmap is in it.
852     SkShader::TileMode tileModes[2];
853     tileModes[0] = state.fImageTileModes[0];
854     tileModes[1] = state.fImageTileModes[1];
855     if (tileModes[0] != SkShader::kClamp_TileMode ||
856             tileModes[1] != SkShader::kClamp_TileMode) {
857         deviceBounds.join(bitmapBounds);
858     }
859 
860     SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()),
861                                  SkScalarRoundToInt(deviceBounds.height()));
862     SkAutoTUnref<SkPDFDevice> patternDevice(
863             SkPDFDevice::CreateUnflipped(size, dpi, canon));
864     SkCanvas canvas(patternDevice.get());
865 
866     SkRect patternBBox;
867     image->getBounds(&patternBBox);
868 
869     // Translate the canvas so that the bitmap origin is at (0, 0).
870     canvas.translate(-deviceBounds.left(), -deviceBounds.top());
871     patternBBox.offset(-deviceBounds.left(), -deviceBounds.top());
872     // Undo the translation in the final matrix
873     finalMatrix.preTranslate(deviceBounds.left(), deviceBounds.top());
874 
875     // If the bitmap is out of bounds (i.e. clamp mode where we only see the
876     // stretched sides), canvas will clip this out and the extraneous data
877     // won't be saved to the PDF.
878     canvas.drawBitmap(*image, 0, 0);
879 
880     SkScalar width = SkIntToScalar(image->width());
881     SkScalar height = SkIntToScalar(image->height());
882 
883     // Tiling is implied.  First we handle mirroring.
884     if (tileModes[0] == SkShader::kMirror_TileMode) {
885         SkMatrix xMirror;
886         xMirror.setScale(-1, 1);
887         xMirror.postTranslate(2 * width, 0);
888         drawBitmapMatrix(&canvas, *image, xMirror);
889         patternBBox.fRight += width;
890     }
891     if (tileModes[1] == SkShader::kMirror_TileMode) {
892         SkMatrix yMirror;
893         yMirror.setScale(SK_Scalar1, -SK_Scalar1);
894         yMirror.postTranslate(0, 2 * height);
895         drawBitmapMatrix(&canvas, *image, yMirror);
896         patternBBox.fBottom += height;
897     }
898     if (tileModes[0] == SkShader::kMirror_TileMode &&
899             tileModes[1] == SkShader::kMirror_TileMode) {
900         SkMatrix mirror;
901         mirror.setScale(-1, -1);
902         mirror.postTranslate(2 * width, 2 * height);
903         drawBitmapMatrix(&canvas, *image, mirror);
904     }
905 
906     // Then handle Clamping, which requires expanding the pattern canvas to
907     // cover the entire surfaceBBox.
908 
909     // If both x and y are in clamp mode, we start by filling in the corners.
910     // (Which are just a rectangles of the corner colors.)
911     if (tileModes[0] == SkShader::kClamp_TileMode &&
912             tileModes[1] == SkShader::kClamp_TileMode) {
913         SkPaint paint;
914         SkRect rect;
915         rect = SkRect::MakeLTRB(deviceBounds.left(), deviceBounds.top(), 0, 0);
916         if (!rect.isEmpty()) {
917             paint.setColor(image->getColor(0, 0));
918             canvas.drawRect(rect, paint);
919         }
920 
921         rect = SkRect::MakeLTRB(width, deviceBounds.top(),
922                                 deviceBounds.right(), 0);
923         if (!rect.isEmpty()) {
924             paint.setColor(image->getColor(image->width() - 1, 0));
925             canvas.drawRect(rect, paint);
926         }
927 
928         rect = SkRect::MakeLTRB(width, height,
929                                 deviceBounds.right(), deviceBounds.bottom());
930         if (!rect.isEmpty()) {
931             paint.setColor(image->getColor(image->width() - 1,
932                                            image->height() - 1));
933             canvas.drawRect(rect, paint);
934         }
935 
936         rect = SkRect::MakeLTRB(deviceBounds.left(), height,
937                                 0, deviceBounds.bottom());
938         if (!rect.isEmpty()) {
939             paint.setColor(image->getColor(0, image->height() - 1));
940             canvas.drawRect(rect, paint);
941         }
942     }
943 
944     // Then expand the left, right, top, then bottom.
945     if (tileModes[0] == SkShader::kClamp_TileMode) {
946         SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height());
947         if (deviceBounds.left() < 0) {
948             SkBitmap left;
949             SkAssertResult(image->extractSubset(&left, subset));
950 
951             SkMatrix leftMatrix;
952             leftMatrix.setScale(-deviceBounds.left(), 1);
953             leftMatrix.postTranslate(deviceBounds.left(), 0);
954             drawBitmapMatrix(&canvas, left, leftMatrix);
955 
956             if (tileModes[1] == SkShader::kMirror_TileMode) {
957                 leftMatrix.postScale(SK_Scalar1, -SK_Scalar1);
958                 leftMatrix.postTranslate(0, 2 * height);
959                 drawBitmapMatrix(&canvas, left, leftMatrix);
960             }
961             patternBBox.fLeft = 0;
962         }
963 
964         if (deviceBounds.right() > width) {
965             SkBitmap right;
966             subset.offset(image->width() - 1, 0);
967             SkAssertResult(image->extractSubset(&right, subset));
968 
969             SkMatrix rightMatrix;
970             rightMatrix.setScale(deviceBounds.right() - width, 1);
971             rightMatrix.postTranslate(width, 0);
972             drawBitmapMatrix(&canvas, right, rightMatrix);
973 
974             if (tileModes[1] == SkShader::kMirror_TileMode) {
975                 rightMatrix.postScale(SK_Scalar1, -SK_Scalar1);
976                 rightMatrix.postTranslate(0, 2 * height);
977                 drawBitmapMatrix(&canvas, right, rightMatrix);
978             }
979             patternBBox.fRight = deviceBounds.width();
980         }
981     }
982 
983     if (tileModes[1] == SkShader::kClamp_TileMode) {
984         SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1);
985         if (deviceBounds.top() < 0) {
986             SkBitmap top;
987             SkAssertResult(image->extractSubset(&top, subset));
988 
989             SkMatrix topMatrix;
990             topMatrix.setScale(SK_Scalar1, -deviceBounds.top());
991             topMatrix.postTranslate(0, deviceBounds.top());
992             drawBitmapMatrix(&canvas, top, topMatrix);
993 
994             if (tileModes[0] == SkShader::kMirror_TileMode) {
995                 topMatrix.postScale(-1, 1);
996                 topMatrix.postTranslate(2 * width, 0);
997                 drawBitmapMatrix(&canvas, top, topMatrix);
998             }
999             patternBBox.fTop = 0;
1000         }
1001 
1002         if (deviceBounds.bottom() > height) {
1003             SkBitmap bottom;
1004             subset.offset(0, image->height() - 1);
1005             SkAssertResult(image->extractSubset(&bottom, subset));
1006 
1007             SkMatrix bottomMatrix;
1008             bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height);
1009             bottomMatrix.postTranslate(0, height);
1010             drawBitmapMatrix(&canvas, bottom, bottomMatrix);
1011 
1012             if (tileModes[0] == SkShader::kMirror_TileMode) {
1013                 bottomMatrix.postScale(-1, 1);
1014                 bottomMatrix.postTranslate(2 * width, 0);
1015                 drawBitmapMatrix(&canvas, bottom, bottomMatrix);
1016             }
1017             patternBBox.fBottom = deviceBounds.height();
1018         }
1019     }
1020 
1021     // Put the canvas into the pattern stream (fContent).
1022     SkAutoTDelete<SkStreamAsset> content(patternDevice->content());
1023 
1024     SkPDFImageShader* imageShader = new SkPDFImageShader(autoState->detach());
1025     imageShader->setData(content.get());
1026 
1027     SkAutoTUnref<SkPDFDict> resourceDict(
1028             patternDevice->createResourceDict());
1029     populate_tiling_pattern_dict(imageShader, patternBBox,
1030                                  resourceDict.get(), finalMatrix);
1031 
1032     imageShader->fShaderState->fImage.unlockPixels();
1033 
1034     canon->addImageShader(imageShader);
1035     return imageShader;
1036 }
1037 
operator ==(const SkPDFShader::State & b) const1038 bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const {
1039     if (fType != b.fType ||
1040             fCanvasTransform != b.fCanvasTransform ||
1041             fShaderTransform != b.fShaderTransform ||
1042             fBBox != b.fBBox) {
1043         return false;
1044     }
1045 
1046     if (fType == SkShader::kNone_GradientType) {
1047         if (fPixelGeneration != b.fPixelGeneration ||
1048                 fPixelGeneration == 0 ||
1049                 fImageTileModes[0] != b.fImageTileModes[0] ||
1050                 fImageTileModes[1] != b.fImageTileModes[1]) {
1051             return false;
1052         }
1053     } else {
1054         if (fInfo.fColorCount != b.fInfo.fColorCount ||
1055                 memcmp(fInfo.fColors, b.fInfo.fColors,
1056                        sizeof(SkColor) * fInfo.fColorCount) != 0 ||
1057                 memcmp(fInfo.fColorOffsets, b.fInfo.fColorOffsets,
1058                        sizeof(SkScalar) * fInfo.fColorCount) != 0 ||
1059                 fInfo.fPoint[0] != b.fInfo.fPoint[0] ||
1060                 fInfo.fTileMode != b.fInfo.fTileMode) {
1061             return false;
1062         }
1063 
1064         switch (fType) {
1065             case SkShader::kLinear_GradientType:
1066                 if (fInfo.fPoint[1] != b.fInfo.fPoint[1]) {
1067                     return false;
1068                 }
1069                 break;
1070             case SkShader::kRadial_GradientType:
1071                 if (fInfo.fRadius[0] != b.fInfo.fRadius[0]) {
1072                     return false;
1073                 }
1074                 break;
1075             case SkShader::kConical_GradientType:
1076                 if (fInfo.fPoint[1] != b.fInfo.fPoint[1] ||
1077                         fInfo.fRadius[0] != b.fInfo.fRadius[0] ||
1078                         fInfo.fRadius[1] != b.fInfo.fRadius[1]) {
1079                     return false;
1080                 }
1081                 break;
1082             case SkShader::kSweep_GradientType:
1083             case SkShader::kNone_GradientType:
1084             case SkShader::kColor_GradientType:
1085                 break;
1086         }
1087     }
1088     return true;
1089 }
1090 
State(const SkShader & shader,const SkMatrix & canvasTransform,const SkIRect & bbox,SkScalar rasterScale)1091 SkPDFShader::State::State(const SkShader& shader, const SkMatrix& canvasTransform,
1092                           const SkIRect& bbox, SkScalar rasterScale)
1093         : fCanvasTransform(canvasTransform),
1094           fBBox(bbox),
1095           fPixelGeneration(0) {
1096     fInfo.fColorCount = 0;
1097     fInfo.fColors = nullptr;
1098     fInfo.fColorOffsets = nullptr;
1099     fShaderTransform = shader.getLocalMatrix();
1100     fImageTileModes[0] = fImageTileModes[1] = SkShader::kClamp_TileMode;
1101 
1102     fType = shader.asAGradient(&fInfo);
1103 
1104     if (fType == SkShader::kNone_GradientType) {
1105         SkMatrix matrix;
1106         if (shader.isABitmap(&fImage, &matrix, fImageTileModes)) {
1107             SkASSERT(matrix.isIdentity());
1108         } else {
1109             // Generic fallback for unsupported shaders:
1110             //  * allocate a bbox-sized bitmap
1111             //  * shade the whole area
1112             //  * use the result as a bitmap shader
1113 
1114             // bbox is in device space. While that's exactly what we want for sizing our bitmap,
1115             // we need to map it into shader space for adjustments (to match
1116             // SkPDFImageShader::Create's behavior).
1117             SkRect shaderRect = SkRect::Make(bbox);
1118             if (!inverse_transform_bbox(canvasTransform, &shaderRect)) {
1119                 fImage.reset();
1120                 return;
1121             }
1122 
1123             // Clamp the bitmap size to about 1M pixels
1124             static const SkScalar kMaxBitmapArea = 1024 * 1024;
1125             SkScalar bitmapArea = rasterScale * bbox.width() * rasterScale * bbox.height();
1126             if (bitmapArea > kMaxBitmapArea) {
1127                 rasterScale *= SkScalarSqrt(kMaxBitmapArea / bitmapArea);
1128             }
1129 
1130             SkISize size = SkISize::Make(SkScalarRoundToInt(rasterScale * bbox.width()),
1131                                          SkScalarRoundToInt(rasterScale * bbox.height()));
1132             SkSize scale = SkSize::Make(SkIntToScalar(size.width()) / shaderRect.width(),
1133                                         SkIntToScalar(size.height()) / shaderRect.height());
1134 
1135             fImage.allocN32Pixels(size.width(), size.height());
1136             fImage.eraseColor(SK_ColorTRANSPARENT);
1137 
1138             SkPaint p;
1139             p.setShader(const_cast<SkShader*>(&shader));
1140 
1141             SkCanvas canvas(fImage);
1142             canvas.scale(scale.width(), scale.height());
1143             canvas.translate(-shaderRect.x(), -shaderRect.y());
1144             canvas.drawPaint(p);
1145 
1146             fShaderTransform.setTranslate(shaderRect.x(), shaderRect.y());
1147             fShaderTransform.preScale(1 / scale.width(), 1 / scale.height());
1148         }
1149         fPixelGeneration = fImage.getGenerationID();
1150     } else {
1151         AllocateGradientInfoStorage();
1152         shader.asAGradient(&fInfo);
1153     }
1154 }
1155 
State(const SkPDFShader::State & other)1156 SkPDFShader::State::State(const SkPDFShader::State& other)
1157   : fType(other.fType),
1158     fCanvasTransform(other.fCanvasTransform),
1159     fShaderTransform(other.fShaderTransform),
1160     fBBox(other.fBBox)
1161 {
1162     // Only gradients supported for now, since that is all that is used.
1163     // If needed, image state copy constructor can be added here later.
1164     SkASSERT(fType != SkShader::kNone_GradientType);
1165 
1166     if (fType != SkShader::kNone_GradientType) {
1167         fInfo = other.fInfo;
1168 
1169         AllocateGradientInfoStorage();
1170         for (int i = 0; i < fInfo.fColorCount; i++) {
1171             fInfo.fColors[i] = other.fInfo.fColors[i];
1172             fInfo.fColorOffsets[i] = other.fInfo.fColorOffsets[i];
1173         }
1174     }
1175 }
1176 
1177 /**
1178  * Create a copy of this gradient state with alpha assigned to RGB luminousity.
1179  * Only valid for gradient states.
1180  */
CreateAlphaToLuminosityState() const1181 SkPDFShader::State* SkPDFShader::State::CreateAlphaToLuminosityState() const {
1182     SkASSERT(fType != SkShader::kNone_GradientType);
1183 
1184     SkPDFShader::State* newState = new SkPDFShader::State(*this);
1185 
1186     for (int i = 0; i < fInfo.fColorCount; i++) {
1187         SkAlpha alpha = SkColorGetA(fInfo.fColors[i]);
1188         newState->fInfo.fColors[i] = SkColorSetARGB(255, alpha, alpha, alpha);
1189     }
1190 
1191     return newState;
1192 }
1193 
1194 /**
1195  * Create a copy of this gradient state with alpha set to fully opaque
1196  * Only valid for gradient states.
1197  */
CreateOpaqueState() const1198 SkPDFShader::State* SkPDFShader::State::CreateOpaqueState() const {
1199     SkASSERT(fType != SkShader::kNone_GradientType);
1200 
1201     SkPDFShader::State* newState = new SkPDFShader::State(*this);
1202     for (int i = 0; i < fInfo.fColorCount; i++) {
1203         newState->fInfo.fColors[i] = SkColorSetA(fInfo.fColors[i],
1204                                                  SK_AlphaOPAQUE);
1205     }
1206 
1207     return newState;
1208 }
1209 
1210 /**
1211  * Returns true if state is a gradient and the gradient has alpha.
1212  */
GradientHasAlpha() const1213 bool SkPDFShader::State::GradientHasAlpha() const {
1214     if (fType == SkShader::kNone_GradientType) {
1215         return false;
1216     }
1217 
1218     for (int i = 0; i < fInfo.fColorCount; i++) {
1219         SkAlpha alpha = SkColorGetA(fInfo.fColors[i]);
1220         if (alpha != SK_AlphaOPAQUE) {
1221             return true;
1222         }
1223     }
1224     return false;
1225 }
1226 
AllocateGradientInfoStorage()1227 void SkPDFShader::State::AllocateGradientInfoStorage() {
1228     fColorData.set(sk_malloc_throw(
1229                fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar))));
1230     fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get());
1231     fInfo.fColorOffsets =
1232             reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount);
1233 }
1234