Пример #1
0
static void convolve_gaussian(GrContext* context,
                              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_pass(context, 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_pass(context, srcRect, dstRect, texture,
                          direction, radius, sigma, true, bounds);
    } else {
        // Draw upper and lower margins with bounds; middle without.
        convolve_gaussian_pass(context, lowerSrcRect, lowerDstRect, texture,
                          direction, radius, sigma, true, bounds);
        convolve_gaussian_pass(context, upperSrcRect, upperDstRect, texture,
                          direction, radius, sigma, true, bounds);
        convolve_gaussian_pass(context, middleSrcRect, middleDstRect, texture,
                          direction, radius, sigma, false, bounds);
    }
}
Пример #2
0
 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);
         }
     }
 }
Пример #3
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();
         }
     }
 }
Пример #4
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);
        }
    }
// test that we can draw an aa-rect at coordinates > 32K (bigger than fixedpoint)
static void test_big_aa_rect(skiatest::Reporter* reporter) {
    SkBitmap output;
    SkPMColor pixel[1];
    output.installPixels(SkImageInfo::MakeN32Premul(1, 1), pixel, 4);

    auto surf = SkSurface::MakeRasterN32Premul(300, 33300);
    SkCanvas* canvas = surf->getCanvas();

    SkRect r = { 0, 33000, 300, 33300 };
    int x = SkScalarRoundToInt(r.left());
    int y = SkScalarRoundToInt(r.top());

    // check that the pixel in question starts as transparent (by the surface)
    if (surf->readPixels(output, x, y)) {
        REPORTER_ASSERT(reporter, 0 == pixel[0]);
    } else {
        REPORTER_ASSERT(reporter, false, "readPixels failed");
    }

    SkPaint paint;
    paint.setAntiAlias(true);
    paint.setColor(SK_ColorWHITE);

    canvas->drawRect(r, paint);

    // Now check that it is BLACK
    if (surf->readPixels(output, x, y)) {
        // don't know what swizzling PMColor did, but white should always
        // appear the same.
        REPORTER_ASSERT(reporter, 0xFFFFFFFF == pixel[0]);
    } else {
        REPORTER_ASSERT(reporter, false, "readPixels failed");
    }
}
Пример #6
0
static void draw_gradients(SkCanvas* canvas,
                           sk_sp<SkShader> (*makeShader)(const SkPoint[2], const SkMatrix&),
                           const SkPoint ptsArray[][2], int numImages) {
    // Use some nice prime numbers for the rectangle and matrix with
    // different scaling along the x and y axes (which is the bug this
    // test addresses, where incorrect order of operations mixed up the axes)
    SkRect rectGrad = {
        SkIntToScalar(43),  SkIntToScalar(61),
        SkIntToScalar(181), SkIntToScalar(167) };
    SkMatrix shaderMat;
    shaderMat.setScale(rectGrad.width(), rectGrad.height());
    shaderMat.postTranslate(rectGrad.left(), rectGrad.top());

    canvas->save();
    for (int i = 0; i < numImages; i++) {
        // Advance line downwards if necessary.
        if (i % IMAGES_X == 0 && i != 0) {
            canvas->restore();
            canvas->translate(0, TESTGRID_Y);
            canvas->save();
        }

        SkPaint paint;
        paint.setShader(makeShader(*ptsArray, shaderMat));
        canvas->drawRect(rectGrad, paint);

        // Advance to next position.
        canvas->translate(TESTGRID_X, 0);
        ptsArray++;
    }
    canvas->restore();
}
Пример #7
0
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);
}
Пример #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;
}
Пример #9
0
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();
}
Пример #10
0
    virtual void onDraw(SkCanvas* canvas) {

        canvas->drawColor(SK_ColorGRAY);

        SkPaint paint;
        paint.setTypeface(fTypeface);

        const char* text = "hamburgerfons";

        // draw text at different point sizes
        const int textSize[] = { 10, 30, 50 };
        const int textYOffset[] = { 10, 40, 100};
        SkASSERT(sizeof(textSize) == sizeof(textYOffset));
        for (size_t y = 0; y < sizeof(textSize) / sizeof(int); ++y) {
            paint.setTextSize(SkIntToScalar(textSize[y]));
            canvas->drawText(text, strlen(text), 10, SkIntToScalar(textYOffset[y]), paint);
        }

        // setup work needed to draw text with different clips
        canvas->translate(10, 160);
        paint.setTextSize(40);

        // compute the bounds of the text
        SkRect bounds;
        paint.measureText(text, strlen(text), &bounds);

        const SkScalar boundsHalfWidth = bounds.width() * SK_ScalarHalf;
        const SkScalar boundsHalfHeight = bounds.height() * SK_ScalarHalf;
        const SkScalar boundsQuarterWidth = boundsHalfWidth * SK_ScalarHalf;
        const SkScalar boundsQuarterHeight = boundsHalfHeight * SK_ScalarHalf;

        SkRect upperLeftClip = SkRect::MakeXYWH(bounds.left(), bounds.top(),
                                                boundsHalfWidth, boundsHalfHeight);
        SkRect lowerRightClip = SkRect::MakeXYWH(bounds.centerX(), bounds.centerY(),
                                                 boundsHalfWidth, boundsHalfHeight);
        SkRect interiorClip = bounds;
        interiorClip.inset(boundsQuarterWidth, boundsQuarterHeight);

        const SkRect clipRects[] = { bounds, upperLeftClip, lowerRightClip, interiorClip };

        SkPaint clipHairline;
        clipHairline.setColor(SK_ColorWHITE);
        clipHairline.setStyle(SkPaint::kStroke_Style);

        for (size_t x = 0; x < sizeof(clipRects) / sizeof(SkRect); ++x) {
            canvas->save();
            canvas->drawRect(clipRects[x], clipHairline);
            paint.setAlpha(0x20);
            canvas->drawText(text, strlen(text), 0, 0, paint);
            canvas->clipRect(clipRects[x]);
            paint.setAlpha(0xFF);
            canvas->drawText(text, strlen(text), 0, 0, paint);
            canvas->restore();
            canvas->translate(0, bounds.height() + SkIntToScalar(25));
        }
    }
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 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);
    }
Пример #13
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);
}
Пример #14
0
    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);
    }
Пример #15
0
static void draw_rect(SkCanvas* canvas, const SkRect& r, SkColor c, SkColorProfileType profile,
                      const SkAlpha aa[]) {
    const SkIRect ir = r.round();

    SkBitmap bm;
    bm.allocN32Pixels(ir.width(), ir.height());
    bm.eraseColor(0xFFFFFFFF);
    SkPixmap pm;
    bm.peekPixels(&pm);

    uint32_t flags = 0;
    if (SkColorGetA(c) == 0xFF) {
        flags |= SkXfermode::kSrcIsOpaque_PM4fFlag;
    }
    if (kSRGB_SkColorProfileType == profile) {
        flags |= SkXfermode::kDstIsSRGB_PM4fFlag;
    }

    const SkXfermode::PM4fState state { nullptr, flags };

    const SkPM4f src = SkColor4f::FromColor(c).premul();
    auto proc1 = SkXfermode::GetPM4fProc1(SkXfermode::kSrcOver_Mode, flags);
    for (int y = 0; y < ir.height()/2; ++y) {
        proc1(state, pm.writable_addr32(0, y), src, ir.width(), aa);
    }

    SkPM4f srcRow[1000];
    for (int i = 0; i < ir.width(); ++i) {
        srcRow[i] = src;
    }
    auto procN = SkXfermode::GetPM4fProcN(SkXfermode::kSrcOver_Mode, flags);
    // +1 to skip a row, so we can see the boundary between proc1 and procN
    for (int y = ir.height()/2 + 1; y < ir.height(); ++y) {
        procN(state, pm.writable_addr32(0, y), srcRow, ir.width(), aa);
    }

    canvas->drawBitmap(bm, r.left(), r.top(), nullptr);
}
Пример #16
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;
            }
        }
Пример #17
0
void TransparencyWin::computeLayerSize()
{
    if (m_transformMode == Untransform) {
        // The meaning of the "transformed" source rect is a little ambigous
        // here. The rest of the code doesn't care about it in the Untransform
        // case since we're using our own happy coordinate system. So we set it
        // to be the source rect since that matches how the code below actually
        // uses the variable: to determine how to translate things to account
        // for the offset of the layer.
        m_transformedSourceRect = m_sourceRect;
    } else if (m_transformMode == KeepTransform && m_layerMode != TextComposite) {
        // FIXME: support clipping for other modes
        IntRect clippedSourceRect = m_sourceRect;
        SkRect clipBounds;
        if (m_destContext->getClipBounds(&clipBounds)) {
            FloatRect clipRect(clipBounds.left(), clipBounds.top(), clipBounds.width(), clipBounds.height());
            clippedSourceRect.intersect(enclosingIntRect(clipRect));
        }
        m_transformedSourceRect = m_orgTransform.mapRect(clippedSourceRect);
    } else
        m_transformedSourceRect = m_orgTransform.mapRect(m_sourceRect);

    m_layerSize = IntSize(m_transformedSourceRect.width(), m_transformedSourceRect.height());
}
Пример #18
0
// 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;
}
Пример #19
0
 *
 *  The portion in the layer, will end up SRC_OVERing the 0x80 layer pixels onto the canvas' red
 *  pixels, making magenta.
 *
 *  Thus the expected result is the upper half to be magenta 0xFF7F0080, and the lower half to be
 *  light blue 0xFF7F7FFF.
 */
DEF_SIMPLE_GM(dont_clip_to_layer, canvas, 120, 120) {
    const SkRect r { 10, 10, 110, 110 };

    // Wrap the entire test inside a red layer, so we don't punch the actual gm's alpha with
    // kSrc_Mode, which makes it hard to view (we like our GMs to have opaque pixels).
    canvas->saveLayer(&r, nullptr);
    canvas->drawColor(SK_ColorRED);

    SkRect r0 = SkRect::MakeXYWH(r.left(), r.top(), r.width(), r.height()/2);

    SkCanvas::SaveLayerRec rec;
    rec.fPaint = nullptr;
    rec.fBounds = &r0;
    rec.fBackdrop = nullptr;
    rec.fSaveLayerFlags = 1 << 31;//SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag;
    canvas->saveLayer(rec);
    do_draw(canvas, r);
    canvas->restore();

    canvas->restore();  // red-layer
}

/** Draw a 2px border around the target, then red behind the target;
    set the clip to match the target, then draw >> the target in blue.
Пример #20
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;
}
Пример #21
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();
    }
Пример #22
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);
}
Пример #23
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);
    }
}
Пример #24
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();
    }
Пример #25
0
static void make_path_line(SkPath* path, const SkRect& bounds) {
    path->moveTo(bounds.left(), bounds.top());
    path->lineTo(bounds.right(), bounds.bottom());
}
Пример #26
0
// 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;
}
Пример #27
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());
}
Пример #28
0
    void onDraw(SkCanvas* canvas) override {

        canvas->drawColor(sk_tool_utils::color_to_565(SK_ColorGRAY));

        SkPaint paint;
        paint.setTypeface(emojiFont.typeface);
        const char* text = emojiFont.text;

        // draw text at different point sizes
        const int textSize[] = { 10, 30, 50, };
        const int textYOffset[] = { 10, 40, 100, };
        SkASSERT(sizeof(textSize) == sizeof(textYOffset));
        size_t y_offset = 0;
        for (size_t y = 0; y < sizeof(textSize) / sizeof(int); y++) {
            paint.setTextSize(SkIntToScalar(textSize[y]));
            canvas->drawText(text, strlen(text), 10, SkIntToScalar(textYOffset[y]), paint);
            y_offset += textYOffset[y];
        }

        // draw with shaders and image filters
        for (int makeLinear = 0; makeLinear < 2; makeLinear++) {
            for (int makeBlur = 0; makeBlur < 2; makeBlur++) {
                for (int makeGray = 0; makeGray < 2; makeGray++) {
                    SkPaint shaderPaint;
                    shaderPaint.setTypeface(paint.getTypeface());
                    if (SkToBool(makeLinear)) {
                        shaderPaint.setShader(MakeLinear())->unref();
                    }

                    if (SkToBool(makeBlur) && SkToBool(makeGray)) {
                        SkAutoTUnref<SkImageFilter> grayScale(make_grayscale(nullptr));
                        SkAutoTUnref<SkImageFilter> blur(make_blur(3.0f, grayScale));
                        shaderPaint.setImageFilter(blur);
                    } else if (SkToBool(makeBlur)) {
                        SkAutoTUnref<SkImageFilter> blur(make_blur(3.0f, nullptr));
                        shaderPaint.setImageFilter(blur);
                    } else if (SkToBool(makeGray)) {
                        SkAutoTUnref<SkImageFilter> grayScale(make_grayscale(nullptr));
                        shaderPaint.setImageFilter(grayScale);
                    }
                    shaderPaint.setTextSize(30);
                    canvas->drawText(text, strlen(text), 380, SkIntToScalar(y_offset),
                                     shaderPaint);
                    y_offset += 32;
                }
            }
        }

        // setup work needed to draw text with different clips
        canvas->translate(10, 160);
        paint.setTextSize(40);

        // compute the bounds of the text
        SkRect bounds;
        paint.measureText(text, strlen(text), &bounds);

        const SkScalar boundsHalfWidth = bounds.width() * SK_ScalarHalf;
        const SkScalar boundsHalfHeight = bounds.height() * SK_ScalarHalf;
        const SkScalar boundsQuarterWidth = boundsHalfWidth * SK_ScalarHalf;
        const SkScalar boundsQuarterHeight = boundsHalfHeight * SK_ScalarHalf;

        SkRect upperLeftClip = SkRect::MakeXYWH(bounds.left(), bounds.top(),
                                                boundsHalfWidth, boundsHalfHeight);
        SkRect lowerRightClip = SkRect::MakeXYWH(bounds.centerX(), bounds.centerY(),
                                                 boundsHalfWidth, boundsHalfHeight);
        SkRect interiorClip = bounds;
        interiorClip.inset(boundsQuarterWidth, boundsQuarterHeight);

        const SkRect clipRects[] = { bounds, upperLeftClip, lowerRightClip, interiorClip };

        SkPaint clipHairline;
        clipHairline.setColor(SK_ColorWHITE);
        clipHairline.setStyle(SkPaint::kStroke_Style);

        for (size_t x = 0; x < sizeof(clipRects) / sizeof(SkRect); ++x) {
            canvas->save();
            canvas->drawRect(clipRects[x], clipHairline);
            paint.setAlpha(0x20);
            canvas->drawText(text, strlen(text), 0, 0, paint);
            canvas->clipRect(clipRects[x]);
            paint.setAlpha(0xFF);
            canvas->drawText(text, strlen(text), 0, 0, paint);
            canvas->restore();
            canvas->translate(0, bounds.height() + SkIntToScalar(25));
        }
    }
Пример #29
0
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());
}
Пример #30
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);
}