Home | History | Annotate | Download | only in pdf
      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 "SkCanvas.h"
     13 #include "SkData.h"
     14 #include "SkPDFCatalog.h"
     15 #include "SkPDFDevice.h"
     16 #include "SkPDFTypes.h"
     17 #include "SkPDFUtils.h"
     18 #include "SkScalar.h"
     19 #include "SkStream.h"
     20 #include "SkTemplates.h"
     21 #include "SkThread.h"
     22 #include "SkTypes.h"
     23 
     24 static void transformBBox(const SkMatrix& matrix, SkRect* bbox) {
     25     SkMatrix inverse;
     26     inverse.reset();
     27     matrix.invert(&inverse);
     28     inverse.mapRect(bbox);
     29 }
     30 
     31 static void unitToPointsMatrix(const SkPoint pts[2], SkMatrix* matrix) {
     32     SkVector    vec = pts[1] - pts[0];
     33     SkScalar    mag = vec.length();
     34     SkScalar    inv = mag ? SkScalarInvert(mag) : 0;
     35 
     36     vec.scale(inv);
     37     matrix->setSinCos(vec.fY, vec.fX);
     38     matrix->preTranslate(pts[0].fX, pts[0].fY);
     39     matrix->preScale(mag, mag);
     40 }
     41 
     42 /* Assumes t + startOffset is on the stack and does a linear interpolation on t
     43    between startOffset and endOffset from prevColor to curColor (for each color
     44    component), leaving the result in component order on the stack.
     45    @param range                  endOffset - startOffset
     46    @param curColor[components]   The current color components.
     47    @param prevColor[components]  The previous color components.
     48    @param result                 The result ps function.
     49  */
     50 static void interpolateColorCode(SkScalar range, SkScalar* curColor,
     51                                  SkScalar* prevColor, int components,
     52                                  SkString* result) {
     53     // Figure out how to scale each color component.
     54     SkAutoSTMalloc<4, SkScalar> multiplierAlloc(components);
     55     SkScalar *multiplier = multiplierAlloc.get();
     56     for (int i = 0; i < components; i++) {
     57         multiplier[i] = SkScalarDiv(curColor[i] - prevColor[i], range);
     58     }
     59 
     60     // Calculate when we no longer need to keep a copy of the input parameter t.
     61     // If the last component to use t is i, then dupInput[0..i - 1] = true
     62     // and dupInput[i .. components] = false.
     63     SkAutoSTMalloc<4, bool> dupInputAlloc(components);
     64     bool *dupInput = dupInputAlloc.get();
     65     dupInput[components - 1] = false;
     66     for (int i = components - 2; i >= 0; i--) {
     67         dupInput[i] = dupInput[i + 1] || multiplier[i + 1] != 0;
     68     }
     69 
     70     if (!dupInput[0] && multiplier[0] == 0) {
     71         result->append("pop ");
     72     }
     73 
     74     for (int i = 0; i < components; i++) {
     75         // If the next components needs t, make a copy.
     76         if (dupInput[i]) {
     77             result->append("dup ");
     78         }
     79 
     80         if (multiplier[i] == 0) {
     81             result->appendScalar(prevColor[i]);
     82             result->append(" ");
     83         } else {
     84             if (multiplier[i] != 1) {
     85                 result->appendScalar(multiplier[i]);
     86                 result->append(" mul ");
     87             }
     88             if (prevColor[i] != 0) {
     89                 result->appendScalar(prevColor[i]);
     90                 result->append(" add ");
     91             }
     92         }
     93 
     94         if (dupInput[i]) {
     95             result->append("exch\n");
     96         }
     97     }
     98 }
     99 
    100 /* Generate Type 4 function code to map t=[0,1) to the passed gradient,
    101    clamping at the edges of the range.  The generated code will be of the form:
    102        if (t < 0) {
    103            return colorData[0][r,g,b];
    104        } else {
    105            if (t < info.fColorOffsets[1]) {
    106                return linearinterpolation(colorData[0][r,g,b],
    107                                           colorData[1][r,g,b]);
    108            } else {
    109                if (t < info.fColorOffsets[2]) {
    110                    return linearinterpolation(colorData[1][r,g,b],
    111                                               colorData[2][r,g,b]);
    112                } else {
    113 
    114                 ...    } else {
    115                            return colorData[info.fColorCount - 1][r,g,b];
    116                        }
    117                 ...
    118            }
    119        }
    120  */
    121 static void gradientFunctionCode(const SkShader::GradientInfo& info,
    122                                  SkString* result) {
    123     /* We want to linearly interpolate from the previous color to the next.
    124        Scale the colors from 0..255 to 0..1 and determine the multipliers
    125        for interpolation.
    126        C{r,g,b}(t, section) = t - offset_(section-1) + t * Multiplier{r,g,b}.
    127      */
    128     static const int kColorComponents = 3;
    129     typedef SkScalar ColorTuple[kColorComponents];
    130     SkAutoSTMalloc<4, ColorTuple> colorDataAlloc(info.fColorCount);
    131     ColorTuple *colorData = colorDataAlloc.get();
    132     const SkScalar scale = SkScalarInvert(SkIntToScalar(255));
    133     for (int i = 0; i < info.fColorCount; i++) {
    134         colorData[i][0] = SkScalarMul(SkColorGetR(info.fColors[i]), scale);
    135         colorData[i][1] = SkScalarMul(SkColorGetG(info.fColors[i]), scale);
    136         colorData[i][2] = SkScalarMul(SkColorGetB(info.fColors[i]), scale);
    137     }
    138 
    139     // Clamp the initial color.
    140     result->append("dup 0 le {pop ");
    141     result->appendScalar(colorData[0][0]);
    142     result->append(" ");
    143     result->appendScalar(colorData[0][1]);
    144     result->append(" ");
    145     result->appendScalar(colorData[0][2]);
    146     result->append(" }\n");
    147 
    148     // The gradient colors.
    149     for (int i = 1 ; i < info.fColorCount; i++) {
    150         result->append("{dup ");
    151         result->appendScalar(info.fColorOffsets[i]);
    152         result->append(" le {");
    153         if (info.fColorOffsets[i - 1] != 0) {
    154             result->appendScalar(info.fColorOffsets[i - 1]);
    155             result->append(" sub\n");
    156         }
    157 
    158         interpolateColorCode(info.fColorOffsets[i] - info.fColorOffsets[i - 1],
    159                              colorData[i], colorData[i - 1], kColorComponents,
    160                              result);
    161         result->append("}\n");
    162     }
    163 
    164     // Clamp the final color.
    165     result->append("{pop ");
    166     result->appendScalar(colorData[info.fColorCount - 1][0]);
    167     result->append(" ");
    168     result->appendScalar(colorData[info.fColorCount - 1][1]);
    169     result->append(" ");
    170     result->appendScalar(colorData[info.fColorCount - 1][2]);
    171 
    172     for (int i = 0 ; i < info.fColorCount; i++) {
    173         result->append("} ifelse\n");
    174     }
    175 }
    176 
    177 /* Map a value of t on the stack into [0, 1) for Repeat or Mirror tile mode. */
    178 static void tileModeCode(SkShader::TileMode mode, SkString* result) {
    179     if (mode == SkShader::kRepeat_TileMode) {
    180         result->append("dup truncate sub\n");  // Get the fractional part.
    181         result->append("dup 0 le {1 add} if\n");  // Map (-1,0) => (0,1)
    182         return;
    183     }
    184 
    185     if (mode == SkShader::kMirror_TileMode) {
    186         // Map t mod 2 into [0, 1, 1, 0].
    187         //               Code                     Stack
    188         result->append("abs "                 // Map negative to positive.
    189                        "dup "                 // t.s t.s
    190                        "truncate "            // t.s t
    191                        "dup "                 // t.s t t
    192                        "cvi "                 // t.s t T
    193                        "2 mod "               // t.s t (i mod 2)
    194                        "1 eq "                // t.s t true|false
    195                        "3 1 roll "            // true|false t.s t
    196                        "sub "                 // true|false 0.s
    197                        "exch "                // 0.s true|false
    198                        "{1 exch sub} if\n");  // 1 - 0.s|0.s
    199     }
    200 }
    201 
    202 static SkString linearCode(const SkShader::GradientInfo& info) {
    203     SkString function("{pop\n");  // Just ditch the y value.
    204     tileModeCode(info.fTileMode, &function);
    205     gradientFunctionCode(info, &function);
    206     function.append("}");
    207     return function;
    208 }
    209 
    210 static SkString radialCode(const SkShader::GradientInfo& info) {
    211     SkString function("{");
    212     // Find the distance from the origin.
    213     function.append("dup "      // x y y
    214                     "mul "      // x y^2
    215                     "exch "     // y^2 x
    216                     "dup "      // y^2 x x
    217                     "mul "      // y^2 x^2
    218                     "add "      // y^2+x^2
    219                     "sqrt\n");  // sqrt(y^2+x^2)
    220 
    221     tileModeCode(info.fTileMode, &function);
    222     gradientFunctionCode(info, &function);
    223     function.append("}");
    224     return function;
    225 }
    226 
    227 /* The math here is all based on the description in Two_Point_Radial_Gradient,
    228    with one simplification, the coordinate space has been scaled so that
    229    Dr = 1.  This means we don't need to scale the entire equation by 1/Dr^2.
    230  */
    231 static SkString twoPointRadialCode(const SkShader::GradientInfo& info) {
    232     SkScalar dx = info.fPoint[0].fX - info.fPoint[1].fX;
    233     SkScalar dy = info.fPoint[0].fY - info.fPoint[1].fY;
    234     SkScalar sr = info.fRadius[0];
    235     SkScalar a = SkScalarMul(dx, dx) + SkScalarMul(dy, dy) - SK_Scalar1;
    236     bool posRoot = info.fRadius[1] > info.fRadius[0];
    237 
    238     // We start with a stack of (x y), copy it and then consume one copy in
    239     // order to calculate b and the other to calculate c.
    240     SkString function("{");
    241     function.append("2 copy ");
    242 
    243     // Calculate -b and b^2.
    244     function.appendScalar(dy);
    245     function.append(" mul exch ");
    246     function.appendScalar(dx);
    247     function.append(" mul add ");
    248     function.appendScalar(sr);
    249     function.append(" sub 2 mul neg dup dup mul\n");
    250 
    251     // Calculate c
    252     function.append("4 2 roll dup mul exch dup mul add ");
    253     function.appendScalar(SkScalarMul(sr, sr));
    254     function.append(" sub\n");
    255 
    256     // Calculate the determinate
    257     function.appendScalar(SkScalarMul(SkIntToScalar(4), a));
    258     function.append(" mul sub abs sqrt\n");
    259 
    260     // And then the final value of t.
    261     if (posRoot) {
    262         function.append("sub ");
    263     } else {
    264         function.append("add ");
    265     }
    266     function.appendScalar(SkScalarMul(SkIntToScalar(2), a));
    267     function.append(" div\n");
    268 
    269     tileModeCode(info.fTileMode, &function);
    270     gradientFunctionCode(info, &function);
    271     function.append("}");
    272     return function;
    273 }
    274 
    275 static SkString sweepCode(const SkShader::GradientInfo& info) {
    276     SkString function("{exch atan 360 div\n");
    277     tileModeCode(info.fTileMode, &function);
    278     gradientFunctionCode(info, &function);
    279     function.append("}");
    280     return function;
    281 }
    282 
    283 class SkPDFShader::State {
    284 public:
    285     SkShader::GradientType fType;
    286     SkShader::GradientInfo fInfo;
    287     SkAutoFree fColorData;
    288     SkMatrix fCanvasTransform;
    289     SkMatrix fShaderTransform;
    290     SkIRect fBBox;
    291 
    292     SkBitmap fImage;
    293     uint32_t fPixelGeneration;
    294     SkShader::TileMode fImageTileModes[2];
    295 
    296     explicit State(const SkShader& shader, const SkMatrix& canvasTransform,
    297                    const SkIRect& bbox);
    298     bool operator==(const State& b) const;
    299 };
    300 
    301 class SkPDFFunctionShader : public SkPDFDict, public SkPDFShader {
    302 public:
    303     explicit SkPDFFunctionShader(SkPDFShader::State* state);
    304     ~SkPDFFunctionShader() {
    305         if (isValid()) {
    306             RemoveShader(this);
    307         }
    308         fResources.unrefAll();
    309     }
    310 
    311     bool isValid() { return fResources.count() > 0; }
    312 
    313     void getResources(SkTDArray<SkPDFObject*>* resourceList) {
    314         GetResourcesHelper(&fResources, resourceList);
    315     }
    316 
    317 private:
    318     static SkPDFObject* RangeObject();
    319 
    320     SkTDArray<SkPDFObject*> fResources;
    321     SkAutoTDelete<const SkPDFShader::State> fState;
    322 
    323     SkPDFStream* makePSFunction(const SkString& psCode, SkPDFArray* domain);
    324 };
    325 
    326 class SkPDFImageShader : public SkPDFStream, public SkPDFShader {
    327 public:
    328     explicit SkPDFImageShader(SkPDFShader::State* state);
    329     ~SkPDFImageShader() {
    330         RemoveShader(this);
    331         fResources.unrefAll();
    332     }
    333 
    334     void getResources(SkTDArray<SkPDFObject*>* resourceList) {
    335         GetResourcesHelper(&fResources, resourceList);
    336     }
    337 
    338 private:
    339     SkTDArray<SkPDFObject*> fResources;
    340     SkAutoTDelete<const SkPDFShader::State> fState;
    341 };
    342 
    343 SkPDFShader::SkPDFShader() {}
    344 
    345 // static
    346 void SkPDFShader::RemoveShader(SkPDFObject* shader) {
    347     SkAutoMutexAcquire lock(CanonicalShadersMutex());
    348     ShaderCanonicalEntry entry(shader, NULL);
    349     int index = CanonicalShaders().find(entry);
    350     SkASSERT(index >= 0);
    351     CanonicalShaders().removeShuffle(index);
    352 }
    353 
    354 // static
    355 SkPDFObject* SkPDFShader::GetPDFShader(const SkShader& shader,
    356                                        const SkMatrix& matrix,
    357                                        const SkIRect& surfaceBBox) {
    358     SkPDFObject* result;
    359     SkAutoMutexAcquire lock(CanonicalShadersMutex());
    360     SkAutoTDelete<State> shaderState(new State(shader, matrix, surfaceBBox));
    361 
    362     ShaderCanonicalEntry entry(NULL, shaderState.get());
    363     int index = CanonicalShaders().find(entry);
    364     if (index >= 0) {
    365         result = CanonicalShaders()[index].fPDFShader;
    366         result->ref();
    367         return result;
    368     }
    369     // The PDFShader takes ownership of the shaderSate.
    370     if (shaderState.get()->fType == SkShader::kNone_GradientType) {
    371         result = new SkPDFImageShader(shaderState.detach());
    372     } else {
    373         SkPDFFunctionShader* functionShader =
    374             new SkPDFFunctionShader(shaderState.detach());
    375         if (!functionShader->isValid()) {
    376             delete functionShader;
    377             return NULL;
    378         }
    379         result = functionShader;
    380     }
    381     entry.fPDFShader = result;
    382     CanonicalShaders().push(entry);
    383     return result;  // return the reference that came from new.
    384 }
    385 
    386 // static
    387 SkTDArray<SkPDFShader::ShaderCanonicalEntry>& SkPDFShader::CanonicalShaders() {
    388     // This initialization is only thread safe with gcc.
    389     static SkTDArray<ShaderCanonicalEntry> gCanonicalShaders;
    390     return gCanonicalShaders;
    391 }
    392 
    393 // static
    394 SkBaseMutex& SkPDFShader::CanonicalShadersMutex() {
    395     // This initialization is only thread safe with gcc or when
    396     // POD-style mutex initialization is used.
    397     SK_DECLARE_STATIC_MUTEX(gCanonicalShadersMutex);
    398     return gCanonicalShadersMutex;
    399 }
    400 
    401 // static
    402 SkPDFObject* SkPDFFunctionShader::RangeObject() {
    403     // This initialization is only thread safe with gcc.
    404     static SkPDFArray* range = NULL;
    405     // This method is only used with CanonicalShadersMutex, so it's safe to
    406     // populate domain.
    407     if (range == NULL) {
    408         range = new SkPDFArray;
    409         range->reserve(6);
    410         range->appendInt(0);
    411         range->appendInt(1);
    412         range->appendInt(0);
    413         range->appendInt(1);
    414         range->appendInt(0);
    415         range->appendInt(1);
    416     }
    417     return range;
    418 }
    419 
    420 SkPDFFunctionShader::SkPDFFunctionShader(SkPDFShader::State* state)
    421         : SkPDFDict("Pattern"),
    422           fState(state) {
    423     SkString (*codeFunction)(const SkShader::GradientInfo& info) = NULL;
    424     SkPoint transformPoints[2];
    425 
    426     // Depending on the type of the gradient, we want to transform the
    427     // coordinate space in different ways.
    428     const SkShader::GradientInfo* info = &fState.get()->fInfo;
    429     transformPoints[0] = info->fPoint[0];
    430     transformPoints[1] = info->fPoint[1];
    431     switch (fState.get()->fType) {
    432         case SkShader::kLinear_GradientType:
    433             codeFunction = &linearCode;
    434             break;
    435         case SkShader::kRadial_GradientType:
    436             transformPoints[1] = transformPoints[0];
    437             transformPoints[1].fX += info->fRadius[0];
    438             codeFunction = &radialCode;
    439             break;
    440         case SkShader::kRadial2_GradientType: {
    441             // Bail out if the radii are the same.  Empty fResources signals
    442             // an error and isValid will return false.
    443             if (info->fRadius[0] == info->fRadius[1]) {
    444                 return;
    445             }
    446             transformPoints[1] = transformPoints[0];
    447             SkScalar dr = info->fRadius[1] - info->fRadius[0];
    448             transformPoints[1].fX += dr;
    449             codeFunction = &twoPointRadialCode;
    450             break;
    451         }
    452         case SkShader::kSweep_GradientType:
    453             transformPoints[1] = transformPoints[0];
    454             transformPoints[1].fX += 1;
    455             codeFunction = &sweepCode;
    456             break;
    457         case SkShader::kColor_GradientType:
    458         case SkShader::kNone_GradientType:
    459         default:
    460             return;
    461     }
    462 
    463     // Move any scaling (assuming a unit gradient) or translation
    464     // (and rotation for linear gradient), of the final gradient from
    465     // info->fPoints to the matrix (updating bbox appropriately).  Now
    466     // the gradient can be drawn on on the unit segment.
    467     SkMatrix mapperMatrix;
    468     unitToPointsMatrix(transformPoints, &mapperMatrix);
    469     SkMatrix finalMatrix = fState.get()->fCanvasTransform;
    470     finalMatrix.preConcat(mapperMatrix);
    471     finalMatrix.preConcat(fState.get()->fShaderTransform);
    472     SkRect bbox;
    473     bbox.set(fState.get()->fBBox);
    474     transformBBox(finalMatrix, &bbox);
    475 
    476     SkRefPtr<SkPDFArray> domain = new SkPDFArray;
    477     domain->unref();  // SkRefPtr and new both took a reference.
    478     domain->reserve(4);
    479     domain->appendScalar(bbox.fLeft);
    480     domain->appendScalar(bbox.fRight);
    481     domain->appendScalar(bbox.fTop);
    482     domain->appendScalar(bbox.fBottom);
    483 
    484     SkString functionCode;
    485     // The two point radial gradient further references fState.get()->fInfo
    486     // in translating from x, y coordinates to the t parameter. So, we have
    487     // to transform the points and radii according to the calculated matrix.
    488     if (fState.get()->fType == SkShader::kRadial2_GradientType) {
    489         SkShader::GradientInfo twoPointRadialInfo = *info;
    490         SkMatrix inverseMapperMatrix;
    491         mapperMatrix.invert(&inverseMapperMatrix);
    492         inverseMapperMatrix.mapPoints(twoPointRadialInfo.fPoint, 2);
    493         twoPointRadialInfo.fRadius[0] =
    494             inverseMapperMatrix.mapRadius(info->fRadius[0]);
    495         twoPointRadialInfo.fRadius[1] =
    496             inverseMapperMatrix.mapRadius(info->fRadius[1]);
    497         functionCode = codeFunction(twoPointRadialInfo);
    498     } else {
    499         functionCode = codeFunction(*info);
    500     }
    501 
    502     SkRefPtr<SkPDFStream> function = makePSFunction(functionCode, domain.get());
    503     // Pass one reference to fResources, SkRefPtr and new both took a reference.
    504     fResources.push(function.get());
    505 
    506     SkRefPtr<SkPDFDict> pdfShader = new SkPDFDict;
    507     pdfShader->unref();  // SkRefPtr and new both took a reference.
    508     pdfShader->insertInt("ShadingType", 1);
    509     pdfShader->insertName("ColorSpace", "DeviceRGB");
    510     pdfShader->insert("Domain", domain.get());
    511     pdfShader->insert("Function", new SkPDFObjRef(function.get()))->unref();
    512 
    513     insertInt("PatternType", 2);
    514     insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
    515     insert("Shading", pdfShader.get());
    516 }
    517 
    518 SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
    519     fState.get()->fImage.lockPixels();
    520 
    521     SkMatrix finalMatrix = fState.get()->fCanvasTransform;
    522     finalMatrix.preConcat(fState.get()->fShaderTransform);
    523     SkRect surfaceBBox;
    524     surfaceBBox.set(fState.get()->fBBox);
    525     transformBBox(finalMatrix, &surfaceBBox);
    526 
    527     SkMatrix unflip;
    528     unflip.setTranslate(0, SkScalarRound(surfaceBBox.height()));
    529     unflip.preScale(SK_Scalar1, -SK_Scalar1);
    530     SkISize size = SkISize::Make(SkScalarRound(surfaceBBox.width()),
    531                                  SkScalarRound(surfaceBBox.height()));
    532     SkPDFDevice pattern(size, size, unflip);
    533     SkCanvas canvas(&pattern);
    534     canvas.translate(-surfaceBBox.fLeft, -surfaceBBox.fTop);
    535     finalMatrix.preTranslate(surfaceBBox.fLeft, surfaceBBox.fTop);
    536 
    537     const SkBitmap* image = &fState.get()->fImage;
    538     int width = image->width();
    539     int height = image->height();
    540     SkShader::TileMode tileModes[2];
    541     tileModes[0] = fState.get()->fImageTileModes[0];
    542     tileModes[1] = fState.get()->fImageTileModes[1];
    543 
    544     canvas.drawBitmap(*image, 0, 0);
    545     SkRect patternBBox = SkRect::MakeXYWH(-surfaceBBox.fLeft, -surfaceBBox.fTop,
    546                                           width, height);
    547 
    548     // Tiling is implied.  First we handle mirroring.
    549     if (tileModes[0] == SkShader::kMirror_TileMode) {
    550         SkMatrix xMirror;
    551         xMirror.setScale(-1, 1);
    552         xMirror.postTranslate(2 * width, 0);
    553         canvas.drawBitmapMatrix(*image, xMirror);
    554         patternBBox.fRight += width;
    555     }
    556     if (tileModes[1] == SkShader::kMirror_TileMode) {
    557         SkMatrix yMirror;
    558         yMirror.setScale(SK_Scalar1, -SK_Scalar1);
    559         yMirror.postTranslate(0, 2 * height);
    560         canvas.drawBitmapMatrix(*image, yMirror);
    561         patternBBox.fBottom += height;
    562     }
    563     if (tileModes[0] == SkShader::kMirror_TileMode &&
    564             tileModes[1] == SkShader::kMirror_TileMode) {
    565         SkMatrix mirror;
    566         mirror.setScale(-1, -1);
    567         mirror.postTranslate(2 * width, 2 * height);
    568         canvas.drawBitmapMatrix(*image, mirror);
    569     }
    570 
    571     // Then handle Clamping, which requires expanding the pattern canvas to
    572     // cover the entire surfaceBBox.
    573 
    574     // If both x and y are in clamp mode, we start by filling in the corners.
    575     // (Which are just a rectangles of the corner colors.)
    576     if (tileModes[0] == SkShader::kClamp_TileMode &&
    577             tileModes[1] == SkShader::kClamp_TileMode) {
    578         SkPaint paint;
    579         SkRect rect;
    580         rect = SkRect::MakeLTRB(surfaceBBox.fLeft, surfaceBBox.fTop, 0, 0);
    581         if (!rect.isEmpty()) {
    582             paint.setColor(image->getColor(0, 0));
    583             canvas.drawRect(rect, paint);
    584         }
    585 
    586         rect = SkRect::MakeLTRB(width, surfaceBBox.fTop, surfaceBBox.fRight, 0);
    587         if (!rect.isEmpty()) {
    588             paint.setColor(image->getColor(width - 1, 0));
    589             canvas.drawRect(rect, paint);
    590         }
    591 
    592         rect = SkRect::MakeLTRB(width, height, surfaceBBox.fRight,
    593                                 surfaceBBox.fBottom);
    594         if (!rect.isEmpty()) {
    595             paint.setColor(image->getColor(width - 1, height - 1));
    596             canvas.drawRect(rect, paint);
    597         }
    598 
    599         rect = SkRect::MakeLTRB(surfaceBBox.fLeft, height, 0,
    600                                 surfaceBBox.fBottom);
    601         if (!rect.isEmpty()) {
    602             paint.setColor(image->getColor(0, height - 1));
    603             canvas.drawRect(rect, paint);
    604         }
    605     }
    606 
    607     // Then expand the left, right, top, then bottom.
    608     if (tileModes[0] == SkShader::kClamp_TileMode) {
    609         SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, height);
    610         if (surfaceBBox.fLeft < 0) {
    611             SkBitmap left;
    612             SkAssertResult(image->extractSubset(&left, subset));
    613 
    614             SkMatrix leftMatrix;
    615             leftMatrix.setScale(-surfaceBBox.fLeft, 1);
    616             leftMatrix.postTranslate(surfaceBBox.fLeft, 0);
    617             canvas.drawBitmapMatrix(left, leftMatrix);
    618 
    619             if (tileModes[1] == SkShader::kMirror_TileMode) {
    620                 leftMatrix.postScale(SK_Scalar1, -SK_Scalar1);
    621                 leftMatrix.postTranslate(0, 2 * height);
    622                 canvas.drawBitmapMatrix(left, leftMatrix);
    623             }
    624             patternBBox.fLeft = 0;
    625         }
    626 
    627         if (surfaceBBox.fRight > width) {
    628             SkBitmap right;
    629             subset.offset(width - 1, 0);
    630             SkAssertResult(image->extractSubset(&right, subset));
    631 
    632             SkMatrix rightMatrix;
    633             rightMatrix.setScale(surfaceBBox.fRight - width, 1);
    634             rightMatrix.postTranslate(width, 0);
    635             canvas.drawBitmapMatrix(right, rightMatrix);
    636 
    637             if (tileModes[1] == SkShader::kMirror_TileMode) {
    638                 rightMatrix.postScale(SK_Scalar1, -SK_Scalar1);
    639                 rightMatrix.postTranslate(0, 2 * height);
    640                 canvas.drawBitmapMatrix(right, rightMatrix);
    641             }
    642             patternBBox.fRight = surfaceBBox.width();
    643         }
    644     }
    645 
    646     if (tileModes[1] == SkShader::kClamp_TileMode) {
    647         SkIRect subset = SkIRect::MakeXYWH(0, 0, width, 1);
    648         if (surfaceBBox.fTop < 0) {
    649             SkBitmap top;
    650             SkAssertResult(image->extractSubset(&top, subset));
    651 
    652             SkMatrix topMatrix;
    653             topMatrix.setScale(SK_Scalar1, -surfaceBBox.fTop);
    654             topMatrix.postTranslate(0, surfaceBBox.fTop);
    655             canvas.drawBitmapMatrix(top, topMatrix);
    656 
    657             if (tileModes[0] == SkShader::kMirror_TileMode) {
    658                 topMatrix.postScale(-1, 1);
    659                 topMatrix.postTranslate(2 * width, 0);
    660                 canvas.drawBitmapMatrix(top, topMatrix);
    661             }
    662             patternBBox.fTop = 0;
    663         }
    664 
    665         if (surfaceBBox.fBottom > height) {
    666             SkBitmap bottom;
    667             subset.offset(0, height - 1);
    668             SkAssertResult(image->extractSubset(&bottom, subset));
    669 
    670             SkMatrix bottomMatrix;
    671             bottomMatrix.setScale(SK_Scalar1, surfaceBBox.fBottom - height);
    672             bottomMatrix.postTranslate(0, height);
    673             canvas.drawBitmapMatrix(bottom, bottomMatrix);
    674 
    675             if (tileModes[0] == SkShader::kMirror_TileMode) {
    676                 bottomMatrix.postScale(-1, 1);
    677                 bottomMatrix.postTranslate(2 * width, 0);
    678                 canvas.drawBitmapMatrix(bottom, bottomMatrix);
    679             }
    680             patternBBox.fBottom = surfaceBBox.height();
    681         }
    682     }
    683 
    684     SkRefPtr<SkPDFArray> patternBBoxArray = new SkPDFArray;
    685     patternBBoxArray->unref();  // SkRefPtr and new both took a reference.
    686     patternBBoxArray->reserve(4);
    687     patternBBoxArray->appendScalar(patternBBox.fLeft);
    688     patternBBoxArray->appendScalar(patternBBox.fTop);
    689     patternBBoxArray->appendScalar(patternBBox.fRight);
    690     patternBBoxArray->appendScalar(patternBBox.fBottom);
    691 
    692     // Put the canvas into the pattern stream (fContent).
    693     SkRefPtr<SkStream> content = pattern.content();
    694     content->unref();  // SkRefPtr and content() both took a reference.
    695     pattern.getResources(&fResources);
    696 
    697     setData(content.get());
    698     insertName("Type", "Pattern");
    699     insertInt("PatternType", 1);
    700     insertInt("PaintType", 1);
    701     insertInt("TilingType", 1);
    702     insert("BBox", patternBBoxArray.get());
    703     insertScalar("XStep", patternBBox.width());
    704     insertScalar("YStep", patternBBox.height());
    705     insert("Resources", pattern.getResourceDict());
    706     insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();
    707 
    708     fState.get()->fImage.unlockPixels();
    709 }
    710 
    711 SkPDFStream* SkPDFFunctionShader::makePSFunction(const SkString& psCode,
    712                                                  SkPDFArray* domain) {
    713     SkAutoDataUnref funcData(SkData::NewWithCopy(psCode.c_str(),
    714                                                  psCode.size()));
    715     SkPDFStream* result = new SkPDFStream(funcData.get());
    716     result->insertInt("FunctionType", 4);
    717     result->insert("Domain", domain);
    718     result->insert("Range", RangeObject());
    719     return result;
    720 }
    721 
    722 SkPDFShader::ShaderCanonicalEntry::ShaderCanonicalEntry(SkPDFObject* pdfShader,
    723                                                         const State* state)
    724     : fPDFShader(pdfShader),
    725       fState(state) {
    726 }
    727 
    728 bool SkPDFShader::ShaderCanonicalEntry::operator==(
    729         const ShaderCanonicalEntry& b) const {
    730     return fPDFShader == b.fPDFShader ||
    731            (fState != NULL && b.fState != NULL && *fState == *b.fState);
    732 }
    733 
    734 bool SkPDFShader::State::operator==(const SkPDFShader::State& b) const {
    735     if (fType != b.fType ||
    736             fCanvasTransform != b.fCanvasTransform ||
    737             fShaderTransform != b.fShaderTransform ||
    738             fBBox != b.fBBox) {
    739         return false;
    740     }
    741 
    742     if (fType == SkShader::kNone_GradientType) {
    743         if (fPixelGeneration != b.fPixelGeneration ||
    744                 fPixelGeneration == 0 ||
    745                 fImageTileModes[0] != b.fImageTileModes[0] ||
    746                 fImageTileModes[1] != b.fImageTileModes[1]) {
    747             return false;
    748         }
    749     } else {
    750         if (fInfo.fColorCount != b.fInfo.fColorCount ||
    751                 memcmp(fInfo.fColors, b.fInfo.fColors,
    752                        sizeof(SkColor) * fInfo.fColorCount) != 0 ||
    753                 memcmp(fInfo.fColorOffsets, b.fInfo.fColorOffsets,
    754                        sizeof(SkScalar) * fInfo.fColorCount) != 0 ||
    755                 fInfo.fPoint[0] != b.fInfo.fPoint[0] ||
    756                 fInfo.fTileMode != b.fInfo.fTileMode) {
    757             return false;
    758         }
    759 
    760         switch (fType) {
    761             case SkShader::kLinear_GradientType:
    762                 if (fInfo.fPoint[1] != b.fInfo.fPoint[1]) {
    763                     return false;
    764                 }
    765                 break;
    766             case SkShader::kRadial_GradientType:
    767                 if (fInfo.fRadius[0] != b.fInfo.fRadius[0]) {
    768                     return false;
    769                 }
    770                 break;
    771             case SkShader::kRadial2_GradientType:
    772                 if (fInfo.fPoint[1] != b.fInfo.fPoint[1] ||
    773                         fInfo.fRadius[0] != b.fInfo.fRadius[0] ||
    774                         fInfo.fRadius[1] != b.fInfo.fRadius[1]) {
    775                     return false;
    776                 }
    777                 break;
    778             case SkShader::kSweep_GradientType:
    779             case SkShader::kNone_GradientType:
    780             case SkShader::kColor_GradientType:
    781                 break;
    782         }
    783     }
    784     return true;
    785 }
    786 
    787 SkPDFShader::State::State(const SkShader& shader,
    788                           const SkMatrix& canvasTransform, const SkIRect& bbox)
    789         : fCanvasTransform(canvasTransform),
    790           fBBox(bbox),
    791           fPixelGeneration(0) {
    792     fInfo.fColorCount = 0;
    793     fInfo.fColors = NULL;
    794     fInfo.fColorOffsets = NULL;
    795     shader.getLocalMatrix(&fShaderTransform);
    796     fImageTileModes[0] = fImageTileModes[1] = SkShader::kClamp_TileMode;
    797 
    798     fType = shader.asAGradient(&fInfo);
    799 
    800     if (fType == SkShader::kNone_GradientType) {
    801         SkShader::BitmapType bitmapType;
    802         SkMatrix matrix;
    803         bitmapType = shader.asABitmap(&fImage, &matrix, fImageTileModes, NULL);
    804         if (bitmapType != SkShader::kDefault_BitmapType) {
    805             fImage.reset();
    806             return;
    807         }
    808         SkASSERT(matrix.isIdentity());
    809         fPixelGeneration = fImage.getGenerationID();
    810     } else {
    811         fColorData.set(sk_malloc_throw(
    812                     fInfo.fColorCount * (sizeof(SkColor) + sizeof(SkScalar))));
    813         fInfo.fColors = reinterpret_cast<SkColor*>(fColorData.get());
    814         fInfo.fColorOffsets =
    815             reinterpret_cast<SkScalar*>(fInfo.fColors + fInfo.fColorCount);
    816         shader.asAGradient(&fInfo);
    817     }
    818 }
    819