static void draw_bbox(SkCanvas* canvas, const SkRect& r) {
    SkPaint paint;
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setColor(0xFFFF7088);
    canvas->drawRect(r, paint);
    canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
    canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
}
Exemple #2
0
void draw(SkCanvas* canvas) {
    SkRect rect = SkRect::MakeLTRB(5, 35, 15, 25);
    SkDebugf("rect: %g, %g, %g, %g  isEmpty: %s\n", rect.left(), rect.top(), rect.right(),
              rect.bottom(), rect.isEmpty() ? "true" : "false");
    rect.sort();
    SkDebugf("rect: %g, %g, %g, %g  isEmpty: %s\n", rect.left(), rect.top(), rect.right(),
              rect.bottom(), rect.isEmpty() ? "true" : "false");
}
static void convolve_gaussian(GrDrawContext* drawContext,
                              GrRenderTarget* rt,
                              const GrClip& clip,
                              const SkRect& srcRect,
                              const SkRect& dstRect,
                              GrTexture* texture,
                              Gr1DKernelEffect::Direction direction,
                              int radius,
                              float sigma,
                              bool cropToSrcRect) {
    float bounds[2] = { 0.0f, 1.0f };
    if (!cropToSrcRect) {
        convolve_gaussian_1d(drawContext, rt, clip, srcRect, dstRect, texture,
                             direction, radius, sigma, false, bounds);
        return;
    }
    SkRect lowerSrcRect = srcRect, lowerDstRect = dstRect;
    SkRect middleSrcRect = srcRect, middleDstRect = dstRect;
    SkRect upperSrcRect = srcRect, upperDstRect = dstRect;
    SkScalar size;
    SkScalar rad = SkIntToScalar(radius);
    if (direction == Gr1DKernelEffect::kX_Direction) {
        bounds[0] = SkScalarToFloat(srcRect.left()) / texture->width();
        bounds[1] = SkScalarToFloat(srcRect.right()) / texture->width();
        size = srcRect.width();
        lowerSrcRect.fRight = srcRect.left() + rad;
        lowerDstRect.fRight = dstRect.left() + rad;
        upperSrcRect.fLeft = srcRect.right() - rad;
        upperDstRect.fLeft = dstRect.right() - rad;
        middleSrcRect.inset(rad, 0);
        middleDstRect.inset(rad, 0);
    } else {
        bounds[0] = SkScalarToFloat(srcRect.top()) / texture->height();
        bounds[1] = SkScalarToFloat(srcRect.bottom()) / texture->height();
        size = srcRect.height();
        lowerSrcRect.fBottom = srcRect.top() + rad;
        lowerDstRect.fBottom = dstRect.top() + rad;
        upperSrcRect.fTop = srcRect.bottom() - rad;
        upperDstRect.fTop = dstRect.bottom() - rad;
        middleSrcRect.inset(0, rad);
        middleDstRect.inset(0, rad);
    }
    if (radius >= size * SK_ScalarHalf) {
        // Blur radius covers srcRect; use bounds over entire draw
        convolve_gaussian_1d(drawContext, rt, clip, srcRect, dstRect, texture,
                            direction, radius, sigma, true, bounds);
    } else {
        // Draw upper and lower margins with bounds; middle without.
        convolve_gaussian_1d(drawContext, rt, clip, lowerSrcRect, lowerDstRect, texture,
                             direction, radius, sigma, true, bounds);
        convolve_gaussian_1d(drawContext, rt, clip, upperSrcRect, upperDstRect, texture,
                             direction, radius, sigma, true, bounds);
        convolve_gaussian_1d(drawContext, rt, clip, middleSrcRect, middleDstRect, texture,
                             direction, radius, sigma, false, bounds);
    }
}
static void draw_box_frame(SkCanvas* canvas, int width, int height) {
    SkPaint p;
    p.setStyle(SkPaint::kStroke_Style);
    p.setColor(SK_ColorRED);
    SkRect r = SkRect::MakeIWH(width, height);
    r.inset(0.5f, 0.5f);
    canvas->drawRect(r, p);
    canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), p);
    canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), p);
}
 void onDraw(SkCanvas* canvas) override {
     SkPaint blurPaint;
     SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(5.0f, 5.0f));
     blurPaint.setImageFilter(blur);
     const SkScalar tile_size = SkIntToScalar(128);
     SkRect bounds;
     if (!canvas->getClipBounds(&bounds)) {
         bounds.setEmpty();
     }
     int ts = SkScalarCeilToInt(tile_size);
     SkImageInfo info = SkImageInfo::MakeN32Premul(ts, ts);
     SkAutoTUnref<SkSurface> tileSurface(canvas->newSurface(info));
     if (!tileSurface.get()) {
         tileSurface.reset(SkSurface::NewRaster(info));
     }
     SkCanvas* tileCanvas = tileSurface->getCanvas();
     for (SkScalar y = bounds.top(); y < bounds.bottom(); y += tile_size) {
         for (SkScalar x = bounds.left(); x < bounds.right(); x += tile_size) {
             tileCanvas->save();
             tileCanvas->clear(0);
             tileCanvas->translate(-x, -y);
             SkRect rect = SkRect::MakeWH(WIDTH, HEIGHT);
             tileCanvas->saveLayer(&rect, &blurPaint);
             SkRRect rrect = SkRRect::MakeRectXY(rect.makeInset(20, 20), 25, 25);
             tileCanvas->clipRRect(rrect, SkRegion::kDifference_Op, true);
             SkPaint paint;
             tileCanvas->drawRect(rect, paint);
             tileCanvas->restore();
             tileCanvas->restore();
             canvas->drawImage(tileSurface->makeImageSnapshot().get(), x, y);
         }
     }
 }
Exemple #6
0
    void onDraw(const int loops, SkCanvas* canvas) override {
        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(2);
        if (fRound) {
            paint.setStrokeJoin(SkPaint::kRound_Join);
        }
        this->setupPaint(&paint);

        const SkRect r = fPath.getBounds();
        switch (fAlign) {
            case kLeft_Align:
                canvas->translate(-r.left(), 0);
                break;
            case kMiddle_Align:
                break;
            case kRight_Align:
                canvas->translate(640 - r.right(), 0);
                break;
        }

        for (int i = 0; i < loops; i++) {
            canvas->drawPath(fPath, paint);
        }
    }
Exemple #7
0
 virtual void onDraw(SkCanvas* canvas) {
     SkPaint paint;
     paint.setImageFilter(SkBlurImageFilter::Create(fSigmaX, fSigmaY))->unref();
     const SkScalar tile_size = SkIntToScalar(128);
     SkRect bounds;
     if (!canvas->getClipBounds(&bounds)) {
         bounds.setEmpty();
     }
     for (SkScalar y = bounds.top(); y < bounds.bottom(); y += tile_size) {
         for (SkScalar x = bounds.left(); x < bounds.right(); x += tile_size) {
             canvas->save();
             canvas->clipRect(SkRect::MakeXYWH(x, y, tile_size, tile_size));
             canvas->saveLayer(NULL, &paint);
             const char* str[] = {
                 "The quick",
                 "brown fox",
                 "jumped over",
                 "the lazy dog.",
             };
             SkPaint textPaint;
             textPaint.setAntiAlias(true);
             textPaint.setTextSize(SkIntToScalar(100));
             int posY = 0;
             for (unsigned i = 0; i < SK_ARRAY_COUNT(str); i++) {
                 posY += 100;
                 canvas->drawText(str[i], strlen(str[i]), SkIntToScalar(0),
                                  SkIntToScalar(posY), textPaint);
             }
             canvas->restore();
             canvas->restore();
         }
     }
 }
Exemple #8
0
Json::Value SkJSONCanvas::makeRect(const SkRect& rect) {
    Json::Value result(Json::arrayValue);
    result.append(Json::Value(rect.left()));
    result.append(Json::Value(rect.top()));
    result.append(Json::Value(rect.right()));
    result.append(Json::Value(rect.bottom()));
    return result;
}
PassRefPtr<JSONObject> LoggingCanvas::objectForSkRect(const SkRect& rect)
{
    RefPtr<JSONObject> rectItem = JSONObject::create();
    rectItem->setNumber("left", rect.left());
    rectItem->setNumber("top", rect.top());
    rectItem->setNumber("right", rect.right());
    rectItem->setNumber("bottom", rect.bottom());
    return rectItem.release();
}
    void drawBorders(SkCanvas* canvas) {
        SkPaint p;
        p.setStyle(SkPaint::kStroke_Style);
        p.setColor(SK_ColorBLUE);

        SkRect r = SkRect::MakeWH(fCell.width() * 2, fCell.height() * 2);
        r.inset(SK_ScalarHalf, SK_ScalarHalf);
        canvas->drawRect(r, p);
        canvas->drawLine(r.left(), r.centerY(), r.right(), r.centerY(), p);
        canvas->drawLine(r.centerX(), r.top(), r.centerX(), r.bottom(), p);
    }
Exemple #11
0
// Return true if the rectangle is aligned to integer boundaries.
// See comments for computeBitmapDrawRects() for how this is used.
static bool areBoundariesIntegerAligned(const SkRect& rect)
{
    // Value is 1.19209e-007. This is the tolerance threshold.
    const float epsilon = std::numeric_limits<float>::epsilon();
    SkIRect roundedRect = roundedIntRect(rect);

    return fabs(rect.x() - roundedRect.x()) < epsilon
        && fabs(rect.y() - roundedRect.y()) < epsilon
        && fabs(rect.right() - roundedRect.right()) < epsilon
        && fabs(rect.bottom() - roundedRect.bottom()) < epsilon;
}
Exemple #12
0
static sk_sp<SkShader> make_shader(const SkRect& bounds) {
    const SkPoint pts[] = {
        { bounds.left(), bounds.top() },
        { bounds.right(), bounds.bottom() },
    };
    const SkColor colors[] = {
        SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK,
        SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW,
    };
    return SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors),
                                        SkShader::kClamp_TileMode);
}
    void writePathVertices(GrDrawBatch::Target* target,
                           GrBatchAtlas* atlas,
                           intptr_t offset,
                           GrColor color,
                           size_t vertexStride,
                           const SkMatrix& viewMatrix,
                           const ShapeData* shapeData) const {
        GrTexture* texture = atlas->getTexture();

        SkScalar dx = shapeData->fBounds.fLeft;
        SkScalar dy = shapeData->fBounds.fTop;
        SkScalar width = shapeData->fBounds.width();
        SkScalar height = shapeData->fBounds.height();

        SkScalar invScale = 1.0f / shapeData->fScale;
        dx *= invScale;
        dy *= invScale;
        width *= invScale;
        height *= invScale;

        SkPoint* positions = reinterpret_cast<SkPoint*>(offset);

        // vertex positions
        // TODO make the vertex attributes a struct
        SkRect r = SkRect::MakeXYWH(dx, dy, width, height);
        positions->setRectFan(r.left(), r.top(), r.right(), r.bottom(), vertexStride);

        // colors
        for (int i = 0; i < kVerticesPerQuad; i++) {
            GrColor* colorPtr = (GrColor*)(offset + sizeof(SkPoint) + i * vertexStride);
            *colorPtr = color;
        }

        const SkScalar tx = SkIntToScalar(shapeData->fAtlasLocation.fX);
        const SkScalar ty = SkIntToScalar(shapeData->fAtlasLocation.fY);

        // vertex texture coords
        SkPoint* textureCoords = (SkPoint*)(offset + sizeof(SkPoint) + sizeof(GrColor));
        textureCoords->setRectFan(tx / texture->width(),
                                  ty / texture->height(),
                                  (tx + shapeData->fBounds.width()) / texture->width(),
                                  (ty + shapeData->fBounds.height())  / texture->height(),
                                  vertexStride);
    }
Exemple #14
0
        void advance(const SkRect& bounds) {
            fCenter += fVelocity;
            if (fCenter.fX > bounds.right()) {
                SkASSERT(fVelocity.fX > 0);
                fVelocity.fX = -fVelocity.fX;
            } else if (fCenter.fX < bounds.left()) {
                SkASSERT(fVelocity.fX < 0);
                fVelocity.fX = -fVelocity.fX;
            }
            if (fCenter.fY > bounds.bottom()) {
                if (fVelocity.fY > 0) {
                    fVelocity.fY = -fVelocity.fY;
                }
            } else if (fCenter.fY < bounds.top()) {
                if (fVelocity.fY < 0) {
                    fVelocity.fY = -fVelocity.fY;
                }
            }

            fScale += fDScale;
            if (fScale > 2 || fScale < SK_Scalar1/2) {
                fDScale = -fDScale;
            }

            fRadian += fDRadian;
            fRadian = SkScalarMod(fRadian, 2 * SK_ScalarPI);

            fAlpha += fDAlpha;
            if (fAlpha > 1) {
                fAlpha = 1;
                fDAlpha = -fDAlpha;
            } else if (fAlpha < 0) {
                fAlpha = 0;
                fDAlpha = -fDAlpha;
            }
        }
Exemple #15
0
static bool equal(const SkRect& a, const SkRect& b) {
    return  SkScalarNearlyEqual(a.left(), b.left()) &&
            SkScalarNearlyEqual(a.top(), b.top()) &&
            SkScalarNearlyEqual(a.right(), b.right()) &&
            SkScalarNearlyEqual(a.bottom(), b.bottom());
}
// Returns true if this method handled the glyph, false if needs to be passed to fallback
//
bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed,
                                             SkScalar sx, SkScalar sy,
                                             GrFontScaler* scaler) {
    if (NULL == fDrawTarget) {
        return true;
    }

    if (NULL == fStrike) {
        fStrike = fContext->getFontCache()->getStrike(scaler, true);
    }

    GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
    if (NULL == glyph || glyph->fBounds.isEmpty()) {
        return true;
    }

    // fallback to color glyph support
    if (kA8_GrMaskFormat != glyph->fMaskFormat) {
        return false;
    }

    SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
    SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
    SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
    SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);

    SkScalar scale = fTextRatio;
    dx *= scale;
    dy *= scale;
    sx += dx;
    sy += dy;
    width *= scale;
    height *= scale;
    SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height);

    // check if we clipped out
    SkRect dstRect;
    const SkMatrix& ctm = fContext->getMatrix();
    (void) ctm.mapRect(&dstRect, glyphRect);
    if (fClipRect.quickReject(SkScalarTruncToInt(dstRect.left()),
                              SkScalarTruncToInt(dstRect.top()),
                              SkScalarTruncToInt(dstRect.right()),
                              SkScalarTruncToInt(dstRect.bottom()))) {
//            SkCLZ(3);    // so we can set a break-point in the debugger
        return true;
    }

    if (NULL == glyph->fPlot) {
        if (!fStrike->glyphTooLargeForAtlas(glyph)) {
            if (fStrike->addGlyphToAtlas(glyph, scaler)) {
                goto HAS_ATLAS;
            }

            // try to clear out an unused plot before we flush
            if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
                fStrike->addGlyphToAtlas(glyph, scaler)) {
                goto HAS_ATLAS;
            }

            if (c_DumpFontCache) {
#ifdef SK_DEVELOPER
                fContext->getFontCache()->dump();
#endif
            }

            // before we purge the cache, we must flush any accumulated draws
            this->flush();
            fContext->flush();

            // we should have an unused plot now
            if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
                fStrike->addGlyphToAtlas(glyph, scaler)) {
                goto HAS_ATLAS;
            }
        }

        if (NULL == glyph->fPath) {
            SkPath* path = SkNEW(SkPath);
            if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
                // flag the glyph as being dead?
                delete path;
                return true;
            }
            glyph->fPath = path;
        }

        // flush any accumulated draws before drawing this glyph as a path.
        this->flush();

        GrContext::AutoMatrix am;
        SkMatrix ctm;
        ctm.setScale(fTextRatio, fTextRatio);
        ctm.postTranslate(sx - dx, sy - dy);
        GrPaint tmpPaint(fPaint);
        am.setPreConcat(fContext, ctm, &tmpPaint);
        GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
        fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);

        // remove this glyph from the vertices we need to allocate
        fTotalVertexCount -= kVerticesPerGlyph;
        return true;
    }

HAS_ATLAS:
    SkASSERT(glyph->fPlot);
    GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
    glyph->fPlot->setDrawToken(drawToken);

    GrTexture* texture = glyph->fPlot->texture();
    SkASSERT(texture);

    if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fTotalVertexCount) {
        this->flush();
        fCurrTexture = texture;
        fCurrTexture->ref();
    }

    bool useColorVerts = !fUseLCDText;

    if (NULL == fVertices) {
        int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
        fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
        fVertices = alloc_vertices(fDrawTarget,
                                   fAllocVertexCount,
                                   useColorVerts);
    }

    SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
    SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
    SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
    SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);

    fVertexBounds.joinNonEmptyArg(glyphRect);

    size_t vertSize = get_vertex_stride(useColorVerts);

    SkPoint* positions = reinterpret_cast<SkPoint*>(
                               reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
    positions->setRectFan(glyphRect.fLeft, glyphRect.fTop, glyphRect.fRight, glyphRect.fBottom,
                          vertSize);

    // The texture coords are last in both the with and without color vertex layouts.
    SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
                               reinterpret_cast<intptr_t>(positions) + vertSize  - sizeof(SkPoint));
    textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
                              SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
                              SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + tw)),
                              SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + th)),
                              vertSize);
    if (useColorVerts) {
        // color comes after position.
        GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
        for (int i = 0; i < 4; ++i) {
            *colors = fPaint.getColor();
            colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
        }
    }

    fCurrVertex += 4;
    
    return true;
}
Exemple #17
0
SkPDFImageShader* SkPDFImageShader::Create(
        SkPDFCanon* canon,
        SkScalar dpi,
        SkAutoTDelete<SkPDFShader::State>* autoState) {
    const SkPDFShader::State& state = **autoState;

    state.fImage.lockPixels();

    // The image shader pattern cell will be drawn into a separate device
    // in pattern cell space (no scaling on the bitmap, though there may be
    // translations so that all content is in the device, coordinates > 0).

    // Map clip bounds to shader space to ensure the device is large enough
    // to handle fake clamping.
    SkMatrix finalMatrix = state.fCanvasTransform;
    finalMatrix.preConcat(state.fShaderTransform);
    SkRect deviceBounds;
    deviceBounds.set(state.fBBox);
    if (!inverse_transform_bbox(finalMatrix, &deviceBounds)) {
        return NULL;
    }

    const SkBitmap* image = &state.fImage;
    SkRect bitmapBounds;
    image->getBounds(&bitmapBounds);

    // For tiling modes, the bounds should be extended to include the bitmap,
    // otherwise the bitmap gets clipped out and the shader is empty and awful.
    // For clamp modes, we're only interested in the clip region, whether
    // or not the main bitmap is in it.
    SkShader::TileMode tileModes[2];
    tileModes[0] = state.fImageTileModes[0];
    tileModes[1] = state.fImageTileModes[1];
    if (tileModes[0] != SkShader::kClamp_TileMode ||
            tileModes[1] != SkShader::kClamp_TileMode) {
        deviceBounds.join(bitmapBounds);
    }

    SkISize size = SkISize::Make(SkScalarRoundToInt(deviceBounds.width()),
                                 SkScalarRoundToInt(deviceBounds.height()));
    SkAutoTUnref<SkPDFDevice> patternDevice(
            SkPDFDevice::CreateUnflipped(size, dpi, canon));
    SkCanvas canvas(patternDevice.get());

    SkRect patternBBox;
    image->getBounds(&patternBBox);

    // Translate the canvas so that the bitmap origin is at (0, 0).
    canvas.translate(-deviceBounds.left(), -deviceBounds.top());
    patternBBox.offset(-deviceBounds.left(), -deviceBounds.top());
    // Undo the translation in the final matrix
    finalMatrix.preTranslate(deviceBounds.left(), deviceBounds.top());

    // If the bitmap is out of bounds (i.e. clamp mode where we only see the
    // stretched sides), canvas will clip this out and the extraneous data
    // won't be saved to the PDF.
    canvas.drawBitmap(*image, 0, 0);

    SkScalar width = SkIntToScalar(image->width());
    SkScalar height = SkIntToScalar(image->height());

    // Tiling is implied.  First we handle mirroring.
    if (tileModes[0] == SkShader::kMirror_TileMode) {
        SkMatrix xMirror;
        xMirror.setScale(-1, 1);
        xMirror.postTranslate(2 * width, 0);
        drawBitmapMatrix(&canvas, *image, xMirror);
        patternBBox.fRight += width;
    }
    if (tileModes[1] == SkShader::kMirror_TileMode) {
        SkMatrix yMirror;
        yMirror.setScale(SK_Scalar1, -SK_Scalar1);
        yMirror.postTranslate(0, 2 * height);
        drawBitmapMatrix(&canvas, *image, yMirror);
        patternBBox.fBottom += height;
    }
    if (tileModes[0] == SkShader::kMirror_TileMode &&
            tileModes[1] == SkShader::kMirror_TileMode) {
        SkMatrix mirror;
        mirror.setScale(-1, -1);
        mirror.postTranslate(2 * width, 2 * height);
        drawBitmapMatrix(&canvas, *image, mirror);
    }

    // Then handle Clamping, which requires expanding the pattern canvas to
    // cover the entire surfaceBBox.

    // If both x and y are in clamp mode, we start by filling in the corners.
    // (Which are just a rectangles of the corner colors.)
    if (tileModes[0] == SkShader::kClamp_TileMode &&
            tileModes[1] == SkShader::kClamp_TileMode) {
        SkPaint paint;
        SkRect rect;
        rect = SkRect::MakeLTRB(deviceBounds.left(), deviceBounds.top(), 0, 0);
        if (!rect.isEmpty()) {
            paint.setColor(image->getColor(0, 0));
            canvas.drawRect(rect, paint);
        }

        rect = SkRect::MakeLTRB(width, deviceBounds.top(),
                                deviceBounds.right(), 0);
        if (!rect.isEmpty()) {
            paint.setColor(image->getColor(image->width() - 1, 0));
            canvas.drawRect(rect, paint);
        }

        rect = SkRect::MakeLTRB(width, height,
                                deviceBounds.right(), deviceBounds.bottom());
        if (!rect.isEmpty()) {
            paint.setColor(image->getColor(image->width() - 1,
                                           image->height() - 1));
            canvas.drawRect(rect, paint);
        }

        rect = SkRect::MakeLTRB(deviceBounds.left(), height,
                                0, deviceBounds.bottom());
        if (!rect.isEmpty()) {
            paint.setColor(image->getColor(0, image->height() - 1));
            canvas.drawRect(rect, paint);
        }
    }

    // Then expand the left, right, top, then bottom.
    if (tileModes[0] == SkShader::kClamp_TileMode) {
        SkIRect subset = SkIRect::MakeXYWH(0, 0, 1, image->height());
        if (deviceBounds.left() < 0) {
            SkBitmap left;
            SkAssertResult(image->extractSubset(&left, subset));

            SkMatrix leftMatrix;
            leftMatrix.setScale(-deviceBounds.left(), 1);
            leftMatrix.postTranslate(deviceBounds.left(), 0);
            drawBitmapMatrix(&canvas, left, leftMatrix);

            if (tileModes[1] == SkShader::kMirror_TileMode) {
                leftMatrix.postScale(SK_Scalar1, -SK_Scalar1);
                leftMatrix.postTranslate(0, 2 * height);
                drawBitmapMatrix(&canvas, left, leftMatrix);
            }
            patternBBox.fLeft = 0;
        }

        if (deviceBounds.right() > width) {
            SkBitmap right;
            subset.offset(image->width() - 1, 0);
            SkAssertResult(image->extractSubset(&right, subset));

            SkMatrix rightMatrix;
            rightMatrix.setScale(deviceBounds.right() - width, 1);
            rightMatrix.postTranslate(width, 0);
            drawBitmapMatrix(&canvas, right, rightMatrix);

            if (tileModes[1] == SkShader::kMirror_TileMode) {
                rightMatrix.postScale(SK_Scalar1, -SK_Scalar1);
                rightMatrix.postTranslate(0, 2 * height);
                drawBitmapMatrix(&canvas, right, rightMatrix);
            }
            patternBBox.fRight = deviceBounds.width();
        }
    }

    if (tileModes[1] == SkShader::kClamp_TileMode) {
        SkIRect subset = SkIRect::MakeXYWH(0, 0, image->width(), 1);
        if (deviceBounds.top() < 0) {
            SkBitmap top;
            SkAssertResult(image->extractSubset(&top, subset));

            SkMatrix topMatrix;
            topMatrix.setScale(SK_Scalar1, -deviceBounds.top());
            topMatrix.postTranslate(0, deviceBounds.top());
            drawBitmapMatrix(&canvas, top, topMatrix);

            if (tileModes[0] == SkShader::kMirror_TileMode) {
                topMatrix.postScale(-1, 1);
                topMatrix.postTranslate(2 * width, 0);
                drawBitmapMatrix(&canvas, top, topMatrix);
            }
            patternBBox.fTop = 0;
        }

        if (deviceBounds.bottom() > height) {
            SkBitmap bottom;
            subset.offset(0, image->height() - 1);
            SkAssertResult(image->extractSubset(&bottom, subset));

            SkMatrix bottomMatrix;
            bottomMatrix.setScale(SK_Scalar1, deviceBounds.bottom() - height);
            bottomMatrix.postTranslate(0, height);
            drawBitmapMatrix(&canvas, bottom, bottomMatrix);

            if (tileModes[0] == SkShader::kMirror_TileMode) {
                bottomMatrix.postScale(-1, 1);
                bottomMatrix.postTranslate(2 * width, 0);
                drawBitmapMatrix(&canvas, bottom, bottomMatrix);
            }
            patternBBox.fBottom = deviceBounds.height();
        }
    }

    // Put the canvas into the pattern stream (fContent).
    SkAutoTDelete<SkStreamAsset> content(patternDevice->content());

    SkPDFImageShader* imageShader =
            SkNEW_ARGS(SkPDFImageShader, (autoState->detach()));
    imageShader->setData(content.get());

    SkAutoTUnref<SkPDFDict> resourceDict(
            patternDevice->createResourceDict());
    populate_tiling_pattern_dict(imageShader, patternBBox,
                                 resourceDict.get(), finalMatrix);

    imageShader->fShaderState->fImage.unlockPixels();

    canon->addImageShader(imageShader);
    return imageShader;
}
Exemple #18
0
static void convolve_gaussian(GrDrawContext* drawContext,
                              const GrClip& clip,
                              const SkRect& srcRect,
                              GrTexture* texture,
                              Gr1DKernelEffect::Direction direction,
                              int radius,
                              float sigma,
                              const SkRect* srcBounds,
                              const SkPoint& srcOffset) {
    float bounds[2] = { 0.0f, 1.0f };
    SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
    if (!srcBounds) {
        convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture,
                             direction, radius, sigma, false, bounds);
        return;
    }
    SkRect midRect = *srcBounds, leftRect, rightRect;
    midRect.offset(srcOffset);
    SkIRect topRect, bottomRect;
    SkScalar rad = SkIntToScalar(radius);
    if (direction == Gr1DKernelEffect::kX_Direction) {
        bounds[0] = SkScalarToFloat(srcBounds->left()) / texture->width();
        bounds[1] = SkScalarToFloat(srcBounds->right()) / texture->width();
        SkRect::MakeLTRB(0, 0, dstRect.right(), midRect.top()).roundOut(&topRect);
        SkRect::MakeLTRB(0, midRect.bottom(), dstRect.right(), dstRect.bottom())
            .roundOut(&bottomRect);
        midRect.inset(rad, 0);
        leftRect = SkRect::MakeLTRB(0, midRect.top(), midRect.left(), midRect.bottom());
        rightRect =
            SkRect::MakeLTRB(midRect.right(), midRect.top(), dstRect.width(), midRect.bottom());
        dstRect.fTop = midRect.top();
        dstRect.fBottom = midRect.bottom();
    } else {
        bounds[0] = SkScalarToFloat(srcBounds->top()) / texture->height();
        bounds[1] = SkScalarToFloat(srcBounds->bottom()) / texture->height();
        SkRect::MakeLTRB(0, 0, midRect.left(), dstRect.bottom()).roundOut(&topRect);
        SkRect::MakeLTRB(midRect.right(), 0, dstRect.right(), dstRect.bottom())
            .roundOut(&bottomRect);;
        midRect.inset(0, rad);
        leftRect = SkRect::MakeLTRB(midRect.left(), 0, midRect.right(), midRect.top());
        rightRect =
            SkRect::MakeLTRB(midRect.left(), midRect.bottom(), midRect.right(), dstRect.height());
        dstRect.fLeft = midRect.left();
        dstRect.fRight = midRect.right();
    }
    if (!topRect.isEmpty()) {
        drawContext->clear(&topRect, 0, false);
    }

    if (!bottomRect.isEmpty()) {
        drawContext->clear(&bottomRect, 0, false);
    }
    if (midRect.isEmpty()) {
        // Blur radius covers srcBounds; use bounds over entire draw
        convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture,
                            direction, radius, sigma, true, bounds);
    } else {
        // Draw right and left margins with bounds; middle without.
        convolve_gaussian_1d(drawContext, clip, leftRect, srcOffset, texture,
                             direction, radius, sigma, true, bounds);
        convolve_gaussian_1d(drawContext, clip, rightRect, srcOffset, texture,
                             direction, radius, sigma, true, bounds);
        convolve_gaussian_1d(drawContext, clip, midRect, srcOffset, texture,
                             direction, radius, sigma, false, bounds);
    }
}
Exemple #19
0
    void onOnceBeforeDraw() override {
        const SkRect fieldBounds = kBounds.makeOutset(kBallSize / 2, kBallSize / 2);
        const SkRRect ball = SkRRect::MakeOval(SkRect::MakeWH(kBallSize, kBallSize));
        const SkRRect paddle = SkRRect::MakeRectXY(SkRect::MakeWH(kPaddleSize.width(),
                                                                  kPaddleSize.height()),
                                                   kPaddleSize.width() / 2,
                                                   kPaddleSize.width() / 2);
        fBall.initialize(ball,
                         SkPoint::Make(kBounds.centerX(), kBounds.centerY()),
                         SkVector::Make(fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax),
                                        fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax)));
        fPaddle0.initialize(paddle,
                            SkPoint::Make(fieldBounds.left() - kPaddleSize.width() / 2,
                                          fieldBounds.centerY()),
                            SkVector::Make(0, 0));
        fPaddle1.initialize(paddle,
                            SkPoint::Make(fieldBounds.right() + kPaddleSize.width() / 2,
                                          fieldBounds.centerY()),
                            SkVector::Make(0, 0));

        // Background decoration.
        SkPath bgPath;
        bgPath.moveTo(kBounds.left() , fieldBounds.top());
        bgPath.lineTo(kBounds.right(), fieldBounds.top());
        bgPath.moveTo(kBounds.left() , fieldBounds.bottom());
        bgPath.lineTo(kBounds.right(), fieldBounds.bottom());
        // TODO: stroke-dash support would come in handy right about now.
        for (uint32_t i = 0; i < kBackgroundDashCount; ++i) {
            bgPath.moveTo(kBounds.centerX(),
                          kBounds.top() + (i + 0.25f) * kBounds.height() / kBackgroundDashCount);
            bgPath.lineTo(kBounds.centerX(),
                          kBounds.top() + (i + 0.75f) * kBounds.height() / kBackgroundDashCount);
        }

        auto bg_path  = sksg::Path::Make(bgPath);
        auto bg_paint = sksg::Color::Make(SK_ColorBLACK);
        bg_paint->setStyle(SkPaint::kStroke_Style);
        bg_paint->setStrokeWidth(kBackgroundStroke);

        auto ball_paint    = sksg::Color::Make(SK_ColorGREEN),
             paddle0_paint = sksg::Color::Make(SK_ColorBLUE),
             paddle1_paint = sksg::Color::Make(SK_ColorRED),
             shadow_paint  = sksg::Color::Make(SK_ColorBLACK);
        ball_paint->setAntiAlias(true);
        paddle0_paint->setAntiAlias(true);
        paddle1_paint->setAntiAlias(true);
        shadow_paint->setAntiAlias(true);
        shadow_paint->setOpacity(kShadowOpacity);

        // Build the scene graph.
        auto group = sksg::Group::Make();
        group->addChild(sksg::Draw::Make(std::move(bg_path), std::move(bg_paint)));
        group->addChild(sksg::Draw::Make(fPaddle0.shadowNode, shadow_paint));
        group->addChild(sksg::Draw::Make(fPaddle1.shadowNode, shadow_paint));
        group->addChild(sksg::Draw::Make(fBall.shadowNode, shadow_paint));
        group->addChild(sksg::Draw::Make(fPaddle0.objectNode, paddle0_paint));
        group->addChild(sksg::Draw::Make(fPaddle1.objectNode, paddle1_paint));
        group->addChild(sksg::Draw::Make(fBall.objectNode, ball_paint));

        // Handle everything in a normalized 1x1 space.
        fContentMatrix = sksg::Matrix<SkMatrix>::Make(
            SkMatrix::MakeRectToRect(SkRect::MakeWH(1, 1),
                                     SkRect::MakeIWH(this->width(), this->height()),
                                     SkMatrix::kFill_ScaleToFit));
        auto root = sksg::TransformEffect::Make(std::move(group), fContentMatrix);
        fScene = sksg::Scene::Make(std::move(root), sksg::AnimatorList());

        // Off we go.
        this->updatePaddleStrategy();
    }
Exemple #20
0
static void make_path_line(SkPath* path, const SkRect& bounds) {
    path->moveTo(bounds.left(), bounds.top());
    path->lineTo(bounds.right(), bounds.bottom());
}
Exemple #21
0
// Convert user-space bounds to grid tiles they cover (LT and RB both inclusive).
void SkTileGrid::userToGrid(const SkRect& user, SkIRect* grid) const {
    grid->fLeft   = SkPin32(user.left()   * fInvWidth , 0, fXTiles - 1);
    grid->fTop    = SkPin32(user.top()    * fInvHeight, 0, fYTiles - 1);
    grid->fRight  = SkPin32(user.right()  * fInvWidth , 0, fXTiles - 1);
    grid->fBottom = SkPin32(user.bottom() * fInvHeight, 0, fYTiles - 1);
}
Exemple #22
0
    void onOnceBeforeDraw() override {
        const SkRect fieldBounds = kBounds.makeOutset(kBallSize / 2, kBallSize / 2);
        const SkRRect ball = SkRRect::MakeOval(SkRect::MakeWH(kBallSize, kBallSize));
        const SkRRect paddle = SkRRect::MakeRectXY(SkRect::MakeWH(kPaddleSize.width(),
                                                                  kPaddleSize.height()),
                                                   kPaddleSize.width() / 2,
                                                   kPaddleSize.width() / 2);
        fBall.initialize(ball,
                         SK_ColorGREEN,
                         SkPoint::Make(kBounds.centerX(), kBounds.centerY()),
                         SkVector::Make(fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax),
                                        fRand.nextRangeScalar(kBallSpeedMin, kBallSpeedMax)));
        fPaddle0.initialize(paddle,
                            SK_ColorBLUE,
                            SkPoint::Make(fieldBounds.left() - kPaddleSize.width() / 2,
                                          fieldBounds.centerY()),
                            SkVector::Make(0, 0));
        fPaddle1.initialize(paddle,
                            SK_ColorRED,
                            SkPoint::Make(fieldBounds.right() + kPaddleSize.width() / 2,
                                          fieldBounds.centerY()),
                            SkVector::Make(0, 0));

        // Background decoration.
        SkPath bgPath;
        bgPath.moveTo(kBounds.left() , fieldBounds.top());
        bgPath.lineTo(kBounds.right(), fieldBounds.top());
        bgPath.moveTo(kBounds.left() , fieldBounds.bottom());
        bgPath.lineTo(kBounds.right(), fieldBounds.bottom());
        // TODO: stroke-dash support would come in handy right about now.
        for (uint32_t i = 0; i < kBackgroundDashCount; ++i) {
            bgPath.moveTo(kBounds.centerX(),
                          kBounds.top() + (i + 0.25f) * kBounds.height() / kBackgroundDashCount);
            bgPath.lineTo(kBounds.centerX(),
                          kBounds.top() + (i + 0.75f) * kBounds.height() / kBackgroundDashCount);
        }

        sk_sp<SkSVGPath> bg = SkSVGPath::Make();
        bg->setPath(bgPath);
        bg->setFill(SkSVGPaint(SkSVGPaint::Type::kNone));
        bg->setStroke(SkSVGPaint(SkSVGColorType(SK_ColorBLACK)));
        bg->setStrokeWidth(SkSVGLength(kBackgroundStroke));

        // Build the SVG DOM tree.
        sk_sp<SkSVGSVG> root = SkSVGSVG::Make();
        root->appendChild(std::move(bg));
        root->appendChild(fPaddle0.shadowNode);
        root->appendChild(fPaddle1.shadowNode);
        root->appendChild(fBall.shadowNode);
        root->appendChild(fPaddle0.objectNode);
        root->appendChild(fPaddle1.objectNode);
        root->appendChild(fBall.objectNode);

        // Handle everything in a normalized 1x1 space.
        root->setViewBox(SkSVGViewBoxType(SkRect::MakeWH(1, 1)));

        fDom = sk_sp<SkSVGDOM>(new SkSVGDOM());
        fDom->setContainerSize(SkSize::Make(this->width(), this->height()));
        fDom->setRoot(std::move(root));

        // Off we go.
        this->updatePaddleStrategy();
    }
// Returns true if this method handled the glyph, false if needs to be passed to fallback
//
bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed,
                                             SkScalar sx, SkScalar sy,
                                             GrFontScaler* scaler) {
    if (NULL == fDrawTarget) {
        return true;
    }

    if (NULL == fStrike) {
        fStrike = fContext->getFontCache()->getStrike(scaler, true);
    }

    GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
    if (NULL == glyph || glyph->fBounds.isEmpty()) {
        return true;
    }

    // fallback to color glyph support
    if (kA8_GrMaskFormat != glyph->fMaskFormat) {
        return false;
    }

    SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
    SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
    SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
    SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);

    SkScalar scale = fTextRatio;
    dx *= scale;
    dy *= scale;
    sx += dx;
    sy += dy;
    width *= scale;
    height *= scale;
    SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height);

    // check if we clipped out
    SkRect dstRect;
    const SkMatrix& ctm = fViewMatrix;
    (void) ctm.mapRect(&dstRect, glyphRect);
    if (fClipRect.quickReject(SkScalarTruncToInt(dstRect.left()),
                              SkScalarTruncToInt(dstRect.top()),
                              SkScalarTruncToInt(dstRect.right()),
                              SkScalarTruncToInt(dstRect.bottom()))) {
        return true;
    }

    if (NULL == glyph->fPlot) {
        // needs to be a separate conditional to avoid over-optimization
        // on Nexus 7 and Nexus 10

        // If the glyph is too large we fall back to paths
        if (!uploadGlyph(glyph, scaler)) {
            if (NULL == glyph->fPath) {
                SkPath* path = SkNEW(SkPath);
                if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
                    // flag the glyph as being dead?
                    delete path;
                    return true;
                }
                glyph->fPath = path;
            }

            // flush any accumulated draws before drawing this glyph as a path.
            this->flush();

            SkMatrix ctm;
            ctm.setScale(fTextRatio, fTextRatio);
            ctm.postTranslate(sx - dx, sy - dy);

            SkPath tmpPath(*glyph->fPath);
            tmpPath.transform(ctm);

            GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
            fContext->drawPath(fRenderTarget, fClip, fPaint, fViewMatrix, tmpPath, strokeInfo);

            // remove this glyph from the vertices we need to allocate
            fTotalVertexCount -= kVerticesPerGlyph;
            return true;
        }
    }

    SkASSERT(glyph->fPlot);
    GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
    glyph->fPlot->setDrawToken(drawToken);

    GrTexture* texture = glyph->fPlot->texture();
    SkASSERT(texture);

    if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fTotalVertexCount) {
        this->flush();
        fCurrTexture = texture;
        fCurrTexture->ref();
    }

    bool useColorVerts = !fUseLCDText;

    if (NULL == fVertices) {
        int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
        fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
        fVertices = alloc_vertices(fDrawTarget,
                                   fAllocVertexCount,
                                   useColorVerts);
    }

    fVertexBounds.joinNonEmptyArg(glyphRect);

    int u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
    int v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
    int u1 = u0 + glyph->fBounds.width() - 2*SK_DistanceFieldInset;
    int v1 = v0 + glyph->fBounds.height() - 2*SK_DistanceFieldInset;

    size_t vertSize = get_vertex_stride(useColorVerts);
    intptr_t vertex = reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex;

    // V0
    SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
    position->set(glyphRect.fLeft, glyphRect.fTop);
    if (useColorVerts) {
        SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
        *color = fPaint.getColor();
    }
    SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize -
                                                              sizeof(SkIPoint16));
    textureCoords->set(u0, v0);
    vertex += vertSize;

    // V1
    position = reinterpret_cast<SkPoint*>(vertex);
    position->set(glyphRect.fLeft, glyphRect.fBottom);
    if (useColorVerts) {
        SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
        *color = fPaint.getColor();
    }
    textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize  - sizeof(SkIPoint16));
    textureCoords->set(u0, v1);
    vertex += vertSize;

    // V2
    position = reinterpret_cast<SkPoint*>(vertex);
    position->set(glyphRect.fRight, glyphRect.fBottom);
    if (useColorVerts) {
        SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
        *color = fPaint.getColor();
    }
    textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize  - sizeof(SkIPoint16));
    textureCoords->set(u1, v1);
    vertex += vertSize;

    // V3
    position = reinterpret_cast<SkPoint*>(vertex);
    position->set(glyphRect.fRight, glyphRect.fTop);
    if (useColorVerts) {
        SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
        *color = fPaint.getColor();
    }
    textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize  - sizeof(SkIPoint16));
    textureCoords->set(u1, v0);

    fCurrVertex += 4;
    
    return true;
}
void draw(SkCanvas* canvas) {
    SkRect result;
    bool intersected = result.intersect({ 10, 40, 50, 80 }, { 30, 60, 70, 90 });
    SkDebugf("%s intersection: %g, %g, %g, %g\n", intersected ? "" : "no ",
             result.left(), result.top(), result.right(), result.bottom());
}
Exemple #25
0
    void draw_stroke(SkCanvas* canvas, const SkPath& path, SkScalar width, SkScalar scale,
            bool drawText) {
        if (path.isEmpty()) {
            return;
        }
        SkRect bounds = path.getBounds();
        this->setWHZ(SkScalarCeilToInt(bounds.right()), drawText 
                ? SkScalarRoundToInt(scale * 3 / 2) : SkScalarRoundToInt(scale),
                SkScalarRoundToInt(950.0f / scale));
        erase(fMinSurface);
        SkPaint paint;
        paint.setColor(0x1f1f0f0f);
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(width * scale * scale);
        paint.setColor(0x3f0f1f3f);
        if (drawText) {
            fMinSurface->getCanvas()->drawPath(path, paint);
            this->copyMinToMax();
            fMaxSurface->draw(canvas, 0, 0, NULL);
        }
        paint.setAntiAlias(true);
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(1);

        paint.setColor(SKELETON_COLOR);
        SkPath scaled;
        SkMatrix matrix;
        matrix.reset();
        matrix.setScale(950 / scale, 950 / scale);
        if (drawText) {
            path.transform(matrix, &scaled);
        } else {
            scaled = path;
        }
        canvas->drawPath(scaled, paint);
        draw_points(canvas, scaled, SKELETON_COLOR, true);

        if (fDrawRibs) {
            draw_ribs(canvas, scaled, width, 0xFF00FF00);
        }

        SkPath fill;

        SkPaint p;
        p.setStyle(SkPaint::kStroke_Style);
        if (drawText) {
            p.setStrokeWidth(width * scale * scale);
        } else {
            p.setStrokeWidth(width);
        }
        p.getFillPath(path, &fill);
        SkPath scaledFill;
        if (drawText) {
            fill.transform(matrix, &scaledFill);
        } else {
            scaledFill = fill;
        }
        paint.setColor(WIREFRAME_COLOR);
        canvas->drawPath(scaledFill, paint);
        draw_points(canvas, scaledFill, WIREFRAME_COLOR, false);
    }
Exemple #26
0
static SkPDFIndirectReference make_function_shader(SkPDFDocument* doc,
                                                   const SkPDFGradientShader::Key& state) {
    SkPoint transformPoints[2];
    const SkShader::GradientInfo& info = state.fInfo;
    SkMatrix finalMatrix = state.fCanvasTransform;
    finalMatrix.preConcat(state.fShaderTransform);

    bool doStitchFunctions = (state.fType == SkShader::kLinear_GradientType ||
                              state.fType == SkShader::kRadial_GradientType ||
                              state.fType == SkShader::kConical_GradientType) &&
                              (SkTileMode)info.fTileMode == SkTileMode::kClamp &&
                              !finalMatrix.hasPerspective();

    int32_t shadingType = 1;
    auto pdfShader = SkPDFMakeDict();
    // The two point radial gradient further references
    // state.fInfo
    // in translating from x, y coordinates to the t parameter. So, we have
    // to transform the points and radii according to the calculated matrix.
    if (doStitchFunctions) {
        pdfShader->insertObject("Function", gradientStitchCode(info));
        shadingType = (state.fType == SkShader::kLinear_GradientType) ? 2 : 3;

        auto extend = SkPDFMakeArray();
        extend->reserve(2);
        extend->appendBool(true);
        extend->appendBool(true);
        pdfShader->insertObject("Extend", std::move(extend));

        std::unique_ptr<SkPDFArray> coords;
        if (state.fType == SkShader::kConical_GradientType) {
            SkScalar r1 = info.fRadius[0];
            SkScalar r2 = info.fRadius[1];
            SkPoint pt1 = info.fPoint[0];
            SkPoint pt2 = info.fPoint[1];
            FixUpRadius(pt1, r1, pt2, r2);

            coords = SkPDFMakeArray(pt1.x(),
                                    pt1.y(),
                                    r1,
                                    pt2.x(),
                                    pt2.y(),
                                    r2);
        } else if (state.fType == SkShader::kRadial_GradientType) {
            const SkPoint& pt1 = info.fPoint[0];
            coords = SkPDFMakeArray(pt1.x(),
                                    pt1.y(),
                                    0,
                                    pt1.x(),
                                    pt1.y(),
                                    info.fRadius[0]);
        } else {
            const SkPoint& pt1 = info.fPoint[0];
            const SkPoint& pt2 = info.fPoint[1];
            coords = SkPDFMakeArray(pt1.x(),
                                    pt1.y(),
                                    pt2.x(),
                                    pt2.y());
        }

        pdfShader->insertObject("Coords", std::move(coords));
    } else {
        // Depending on the type of the gradient, we want to transform the
        // coordinate space in different ways.
        transformPoints[0] = info.fPoint[0];
        transformPoints[1] = info.fPoint[1];
        switch (state.fType) {
            case SkShader::kLinear_GradientType:
                break;
            case SkShader::kRadial_GradientType:
                transformPoints[1] = transformPoints[0];
                transformPoints[1].fX += info.fRadius[0];
                break;
            case SkShader::kConical_GradientType: {
                transformPoints[1] = transformPoints[0];
                transformPoints[1].fX += SK_Scalar1;
                break;
            }
            case SkShader::kSweep_GradientType:
                transformPoints[1] = transformPoints[0];
                transformPoints[1].fX += SK_Scalar1;
                break;
            case SkShader::kColor_GradientType:
            case SkShader::kNone_GradientType:
            default:
                return SkPDFIndirectReference();
        }

        // Move any scaling (assuming a unit gradient) or translation
        // (and rotation for linear gradient), of the final gradient from
        // info.fPoints to the matrix (updating bbox appropriately).  Now
        // the gradient can be drawn on on the unit segment.
        SkMatrix mapperMatrix;
        unit_to_points_matrix(transformPoints, &mapperMatrix);

        finalMatrix.preConcat(mapperMatrix);

        // Preserves as much as possible in the final matrix, and only removes
        // the perspective. The inverse of the perspective is stored in
        // perspectiveInverseOnly matrix and has 3 useful numbers
        // (p0, p1, p2), while everything else is either 0 or 1.
        // In this way the shader will handle it eficiently, with minimal code.
        SkMatrix perspectiveInverseOnly = SkMatrix::I();
        if (finalMatrix.hasPerspective()) {
            if (!split_perspective(finalMatrix,
                                   &finalMatrix, &perspectiveInverseOnly)) {
                return SkPDFIndirectReference();
            }
        }

        SkRect bbox;
        bbox.set(state.fBBox);
        if (!SkPDFUtils::InverseTransformBBox(finalMatrix, &bbox)) {
            return SkPDFIndirectReference();
        }
        SkDynamicMemoryWStream functionCode;

        SkShader::GradientInfo infoCopy = info;

        if (state.fType == SkShader::kConical_GradientType) {
            SkMatrix inverseMapperMatrix;
            if (!mapperMatrix.invert(&inverseMapperMatrix)) {
                return SkPDFIndirectReference();
            }
            inverseMapperMatrix.mapPoints(infoCopy.fPoint, 2);
            infoCopy.fRadius[0] = inverseMapperMatrix.mapRadius(info.fRadius[0]);
            infoCopy.fRadius[1] = inverseMapperMatrix.mapRadius(info.fRadius[1]);
        }
        switch (state.fType) {
            case SkShader::kLinear_GradientType:
                linearCode(infoCopy, perspectiveInverseOnly, &functionCode);
                break;
            case SkShader::kRadial_GradientType:
                radialCode(infoCopy, perspectiveInverseOnly, &functionCode);
                break;
            case SkShader::kConical_GradientType:
                twoPointConicalCode(infoCopy, perspectiveInverseOnly, &functionCode);
                break;
            case SkShader::kSweep_GradientType:
                sweepCode(infoCopy, perspectiveInverseOnly, &functionCode);
                break;
            default:
                SkASSERT(false);
        }
        pdfShader->insertObject(
                "Domain", SkPDFMakeArray(bbox.left(), bbox.right(), bbox.top(), bbox.bottom()));

        auto domain = SkPDFMakeArray(bbox.left(), bbox.right(), bbox.top(), bbox.bottom());
        std::unique_ptr<SkPDFArray> rangeObject = SkPDFMakeArray(0, 1, 0, 1, 0, 1);
        pdfShader->insertRef("Function",
                             make_ps_function(functionCode.detachAsStream(), std::move(domain),
                                              std::move(rangeObject), doc));
    }

    pdfShader->insertInt("ShadingType", shadingType);
    pdfShader->insertName("ColorSpace", "DeviceRGB");

    SkPDFDict pdfFunctionShader("Pattern");
    pdfFunctionShader.insertInt("PatternType", 2);
    pdfFunctionShader.insertObject("Matrix", SkPDFUtils::MatrixToArray(finalMatrix));
    pdfFunctionShader.insertObject("Shading", std::move(pdfShader));
    return doc->emit(pdfFunctionShader);
}