示例#1
0
    /**
     * Called on a background thread. Here we can only modify fBackMatrices.
     */
    virtual void runAnimationTask(double t, double dt, int w, int h) {
        for (int idx = 0; idx < kNumPaths; ++idx) {
            Velocity* v = &fVelocities[idx];
            Glyph* glyph = &fGlyphs[idx];
            SkMatrix* backMatrix = &fBackMatrices[idx];

            glyph->fPosition.fX += v->fDx * dt;
            if (glyph->fPosition.x() < 0) {
                glyph->fPosition.fX -= 2 * glyph->fPosition.x();
                v->fDx = -v->fDx;
            } else if (glyph->fPosition.x() > w) {
                glyph->fPosition.fX -= 2 * (glyph->fPosition.x() - w);
                v->fDx = -v->fDx;
            }

            glyph->fPosition.fY += v->fDy * dt;
            if (glyph->fPosition.y() < 0) {
                glyph->fPosition.fY -= 2 * glyph->fPosition.y();
                v->fDy = -v->fDy;
            } else if (glyph->fPosition.y() > h) {
                glyph->fPosition.fY -= 2 * (glyph->fPosition.y() - h);
                v->fDy = -v->fDy;
            }

            glyph->fSpin += v->fDSpin * dt;

            backMatrix->setTranslate(glyph->fPosition.x(), glyph->fPosition.y());
            backMatrix->preScale(glyph->fZoom, glyph->fZoom);
            backMatrix->preRotate(glyph->fSpin);
            backMatrix->preTranslate(-glyph->fMidpt.x(), -glyph->fMidpt.y());
        }
    }
示例#2
0
文件: shapes.cpp 项目: BBKeeper/Skia
    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkMatrix matrix;

        SkGroupShape* gs = new SkGroupShape;
        SkAutoUnref aur(gs);
        gs->appendShape(&fGroup);
        matrix.setScale(-SK_Scalar1, SK_Scalar1);
        matrix.postTranslate(SkIntToScalar(220), SkIntToScalar(240));
        gs->appendShape(&fGroup, matrix);
        matrix.setTranslate(SkIntToScalar(240), 0);
        matrix.preScale(SK_Scalar1*2, SK_Scalar1*2);
        gs->appendShape(&fGroup, matrix);

#if 1
        SkPicture* pict = new SkPicture;
        SkCanvas* cv = pict->beginRecording(1000, 1000);
        cv->scale(SK_ScalarHalf, SK_ScalarHalf);
        gs->draw(cv);
        cv->translate(SkIntToScalar(680), SkIntToScalar(480));
        cv->scale(-SK_Scalar1, SK_Scalar1);
        gs->draw(cv);
        pict->endRecording();
        canvas->drawPicture(*pict);
        pict->unref();
#endif
}
示例#3
0
void GeneratedImage::drawPattern(GraphicsContext& destContext,
                                 const FloatRect& srcRect,
                                 const FloatSize& scale,
                                 const FloatPoint& phase,
                                 SkBlendMode compositeOp,
                                 const FloatRect& destRect,
                                 const FloatSize& repeatSpacing) {
  FloatRect tileRect = srcRect;
  tileRect.expand(FloatSize(repeatSpacing));

  std::unique_ptr<PaintController> paintController = PaintController::create();
  GraphicsContext context(*paintController);
  context.beginRecording(tileRect);
  drawTile(context, srcRect);
  sk_sp<SkPicture> tilePicture = context.endRecording();

  SkMatrix patternMatrix = SkMatrix::MakeTrans(phase.x(), phase.y());
  patternMatrix.preScale(scale.width(), scale.height());
  patternMatrix.preTranslate(tileRect.x(), tileRect.y());

  RefPtr<Pattern> picturePattern =
      Pattern::createPicturePattern(std::move(tilePicture));

  SkPaint fillPaint = destContext.fillPaint();
  picturePattern->applyToPaint(fillPaint, patternMatrix);
  fillPaint.setColor(SK_ColorBLACK);
  fillPaint.setBlendMode(compositeOp);

  destContext.drawRect(destRect, fillPaint);
}
示例#4
0
static void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) {
    SkRect larger = one.getBounds();
    larger.join(two.getBounds());
    SkScalar largerWidth = larger.width();
    if (largerWidth < 4) {
        largerWidth = 4;
    }
    SkScalar largerHeight = larger.height();
    if (largerHeight < 4) {
        largerHeight = 4;
    }
    SkScalar hScale = (bitWidth - 2) / largerWidth;
    SkScalar vScale = (bitHeight - 2) / largerHeight;
    scale.reset();
    scale.preScale(hScale, vScale);
    larger.fLeft *= hScale;
    larger.fRight *= hScale;
    larger.fTop *= vScale;
    larger.fBottom *= vScale;
    SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft
            : 16000 < larger.fRight ? 16000 - larger.fRight : 0;
    SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop
            : 16000 < larger.fBottom ? 16000 - larger.fBottom : 0;
    scale.postTranslate(dx, dy);
}
    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);
        
        SkMatrix saveM = *fMatrixRefs[3];
        SkScalar c = SkIntToScalar(50);
        fMatrixRefs[3]->preRotate(SkIntToScalar(30), c, c);
        
        SkMatrix matrix;
     
        SkGroupShape* gs = new SkGroupShape;
        SkAutoUnref aur(gs);
        gs->appendShape(&fGroup);
        matrix.setScale(-SK_Scalar1, SK_Scalar1);
        matrix.postTranslate(SkIntToScalar(220), SkIntToScalar(240));
        gs->appendShape(&fGroup, matrix);
        matrix.setTranslate(SkIntToScalar(240), 0);
        matrix.preScale(SK_Scalar1*2, SK_Scalar1*2);
        gs->appendShape(&fGroup, matrix);
        
#if 0        
        canvas->drawShape(gs);
#else
        SkPicture pict;
        SkCanvas* cv = pict.beginRecording(1000, 1000);
        cv->scale(SK_ScalarHalf, SK_ScalarHalf);
        cv->drawShape(gs);
        cv->translate(SkIntToScalar(680), SkIntToScalar(480));
        cv->scale(-SK_Scalar1, SK_Scalar1);
        cv->drawShape(gs);
        pict.endRecording();
        canvas->drawPicture(pict);
#endif

        *fMatrixRefs[3] = saveM;
}
示例#6
0
void Image::drawPattern(GraphicsContext* context, const FloatRect& floatSrcRect, const FloatSize& scale,
    const FloatPoint& phase, SkXfermode::Mode compositeOp, const FloatRect& destRect, const IntSize& repeatSpacing)
{
    TRACE_EVENT0("skia", "Image::drawPattern");
    SkBitmap bitmap;
    if (!bitmapForCurrentFrame(&bitmap))
        return;

    FloatRect normSrcRect = floatSrcRect;

    normSrcRect.intersect(FloatRect(0, 0, bitmap.width(), bitmap.height()));
    if (destRect.isEmpty() || normSrcRect.isEmpty())
        return; // nothing to draw

    SkMatrix localMatrix;
    // We also need to translate it such that the origin of the pattern is the
    // origin of the destination rect, which is what WebKit expects. Skia uses
    // the coordinate system origin as the base for the pattern. If WebKit wants
    // a shifted image, it will shift it from there using the localMatrix.
    const float adjustedX = phase.x() + normSrcRect.x() * scale.width();
    const float adjustedY = phase.y() + normSrcRect.y() * scale.height();
    localMatrix.setTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY));

    // Because no resizing occurred, the shader transform should be
    // set to the pattern's transform, which just includes scale.
    localMatrix.preScale(scale.width(), scale.height());

    SkBitmap bitmapToPaint;
    bitmap.extractSubset(&bitmapToPaint, enclosingIntRect(normSrcRect));
    if (!repeatSpacing.isZero()) {
        SkScalar ctmScaleX = 1.0;
        SkScalar ctmScaleY = 1.0;

        if (!RuntimeEnabledFeatures::slimmingPaintEnabled()) {
            AffineTransform ctm = context->getCTM();
            ctmScaleX = ctm.xScale();
            ctmScaleY = ctm.yScale();
        }

        bitmapToPaint = createBitmapWithSpace(
            bitmapToPaint,
            repeatSpacing.width() * ctmScaleX / scale.width(),
            repeatSpacing.height() * ctmScaleY / scale.height());
    }
    RefPtr<SkShader> shader = adoptRef(SkShader::CreateBitmapShader(bitmapToPaint, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));

    bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap);
    {
        SkPaint paint;
        int initialSaveCount = context->preparePaintForDrawRectToRect(&paint, floatSrcRect,
            destRect, compositeOp, !bitmap.isOpaque(), isLazyDecoded, bitmap.isImmutable());
        paint.setShader(shader.get());
        context->drawRect(destRect, paint);
        context->canvas()->restoreToCount(initialSaveCount);
    }

    if (isLazyDecoded)
        PlatformInstrumentation::didDrawLazyPixelRef(bitmap.getGenerationID());
}
示例#7
0
void Matrix::NativePreScale(
    /* [in] */ Int64 nObj,
    /* [in] */ Float sx,
    /* [in] */ Float sy)
{
    SkMatrix* obj = reinterpret_cast<SkMatrix*>(nObj);
    obj->preScale(sx, sy);
}
示例#8
0
void draw(SkCanvas* canvas) {
    SkMatrix matrix;
    SkPoint bitmapBounds[4], perspect[4] = {{50, 10}, {180, 40}, {236, 176}, {10, 206}};
    SkRect::Make(source.bounds()).toQuad(bitmapBounds);
    matrix.setPolyToPoly(bitmapBounds, perspect, 4);
    matrix.preScale(.75f, 1.5f, source.width() / 2, source.height() / 2);
    canvas->concat(matrix);
    canvas->drawBitmap(source, 0, 0);
}
示例#9
0
文件: Image.cpp 项目: mirror/chromium
void Image::drawPattern(GraphicsContext& context,
                        const FloatRect& floatSrcRect,
                        const FloatSize& scale,
                        const FloatPoint& phase,
                        SkBlendMode compositeOp,
                        const FloatRect& destRect,
                        const FloatSize& repeatSpacing) {
  TRACE_EVENT0("skia", "Image::drawPattern");

  sk_sp<SkImage> image = imageForCurrentFrame();
  if (!image)
    return;

  FloatRect normSrcRect = floatSrcRect;

  normSrcRect.intersect(FloatRect(0, 0, image->width(), image->height()));
  if (destRect.isEmpty() || normSrcRect.isEmpty())
    return;  // nothing to draw

  SkMatrix localMatrix;
  // We also need to translate it such that the origin of the pattern is the
  // origin of the destination rect, which is what WebKit expects. Skia uses
  // the coordinate system origin as the base for the pattern. If WebKit wants
  // a shifted image, it will shift it from there using the localMatrix.
  const float adjustedX = phase.x() + normSrcRect.x() * scale.width();
  const float adjustedY = phase.y() + normSrcRect.y() * scale.height();
  localMatrix.setTranslate(SkFloatToScalar(adjustedX),
                           SkFloatToScalar(adjustedY));

  // Because no resizing occurred, the shader transform should be
  // set to the pattern's transform, which just includes scale.
  localMatrix.preScale(scale.width(), scale.height());

  // Fetch this now as subsetting may swap the image.
  auto imageID = image->uniqueID();

  image = image->makeSubset(enclosingIntRect(normSrcRect));
  if (!image)
    return;

  {
    SkPaint paint = context.fillPaint();
    paint.setColor(SK_ColorBLACK);
    paint.setBlendMode(static_cast<SkBlendMode>(compositeOp));
    paint.setFilterQuality(
        context.computeFilterQuality(this, destRect, normSrcRect));
    paint.setAntiAlias(context.shouldAntialias());
    paint.setShader(createPatternShader(
        image.get(), localMatrix, paint,
        FloatSize(repeatSpacing.width() / scale.width(),
                  repeatSpacing.height() / scale.height())));
    context.drawRect(destRect, paint);
  }

  if (currentFrameIsLazyDecoded())
    PlatformInstrumentation::didDrawLazyPixelRef(imageID);
}
示例#10
0
SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatrix* localM) const {
    SkASSERT(fPicture && fPicture->width() > 0 && fPicture->height() > 0);

    SkMatrix m;
    m.setConcat(matrix, this->getLocalMatrix());
    if (localM) {
        m.preConcat(*localM);
    }

    // Use a rotation-invariant scale
    SkPoint scale;
    if (!SkDecomposeUpper2x2(m, NULL, &scale, NULL)) {
        // Decomposition failed, use an approximation.
        scale.set(SkScalarSqrt(m.getScaleX() * m.getScaleX() + m.getSkewX() * m.getSkewX()),
                  SkScalarSqrt(m.getScaleY() * m.getScaleY() + m.getSkewY() * m.getSkewY()));
    }
    SkSize scaledSize = SkSize::Make(scale.x() * fPicture->width(), scale.y() * fPicture->height());

    SkISize tileSize = scaledSize.toRound();
    if (tileSize.isEmpty()) {
        return NULL;
    }

    // The actual scale, compensating for rounding.
    SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(),
                                    SkIntToScalar(tileSize.height()) / fPicture->height());

    SkAutoMutexAcquire ama(fCachedBitmapShaderMutex);

    if (!fCachedBitmapShader || tileScale != fCachedTileScale) {
        SkBitmap bm;
        if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) {
            return NULL;
        }
        bm.eraseColor(SK_ColorTRANSPARENT);

        SkCanvas canvas(bm);
        canvas.scale(tileScale.width(), tileScale.height());
        canvas.drawPicture(fPicture);

        fCachedTileScale = tileScale;

        SkMatrix shaderMatrix = this->getLocalMatrix();
        shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
        fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy, &shaderMatrix));
    }

    // Increment the ref counter inside the mutex to ensure the returned pointer is still valid.
    // Otherwise, the pointer may have been overwritten on a different thread before the object's
    // ref count was incremented.
    fCachedBitmapShader.get()->ref();
    return fCachedBitmapShader;
}
示例#11
0
static bool check_decompScale(const SkMatrix& matrix) {
    SkSize scale;
    SkMatrix remaining;

    if (!matrix.decomposeScale(&scale, &remaining)) {
        return false;
    }
    if (scale.width() <= 0 || scale.height() <= 0) {
        return false;
    }
    remaining.preScale(scale.width(), scale.height());
    return nearly_equal(matrix, remaining);
}
示例#12
0
static int scaledDrawTheSame(const SkPath& one, const SkPath& two,
        int a, int b, bool drawPaths, SkBitmap& bitmap, SkCanvas* canvas) {
    SkMatrix scale;
    scale.reset();
    float aScale = 1.21f;
    float bScale = 1.11f;
    scale.preScale(a * aScale, b * bScale);
    SkPath scaledOne, scaledTwo;
    one.transform(scale, &scaledOne);
    two.transform(scale, &scaledTwo);
    int errors = pathsDrawTheSame(scaledOne, scaledTwo, bitmap, canvas);
    if (errors == 0) {
        return 0;
    }
    while (!drawAsciiPaths(scaledOne, scaledTwo, drawPaths)) {
        scale.reset();
        aScale *= 0.5f;
        bScale *= 0.5f;
        scale.preScale(a * aScale, b * bScale);
        one.transform(scale, &scaledOne);
        two.transform(scale, &scaledTwo);
    }
    return errors;
}
示例#13
0
static void scaleMatrix(const SkPath& one, const SkPath& two, SkMatrix& scale) {
    SkRect larger = one.getBounds();
    larger.join(two.getBounds());
    SkScalar largerWidth = larger.width();
    if (largerWidth < 4) {
        largerWidth = 4;
    }
    SkScalar largerHeight = larger.height();
    if (largerHeight < 4) {
        largerHeight = 4;
    }
    SkScalar hScale = (bitWidth - 2) / largerWidth;
    SkScalar vScale = (bitHeight - 2) / largerHeight;
    scale.reset();
    scale.preScale(hScale, vScale);
}
示例#14
0
void SkGlyphCache::dump() const {
    const SkTypeface* face = fScalerContext->getTypeface();
    const SkScalerContextRec& rec = fScalerContext->getRec();
    SkMatrix matrix;
    rec.getSingleMatrix(&matrix);
    matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize));
    SkString name;
    face->getFamilyName(&name);

    SkString msg;
    SkFontStyle style = face->fontStyle();
    msg.printf("cache typeface:%x %25s:(%d,%d,%d)\n %s glyphs:%3d",
               face->uniqueID(), name.c_str(), style.weight(), style.width(), style.slant(),
               rec.dump().c_str(), fGlyphMap.count());
    SkDebugf("%s\n", msg.c_str());
}
示例#15
0
    virtual void onDrawContent(SkCanvas* canvas) {
        SkScalar angle = SampleCode::GetAnimScalar(SkIntToScalar(180),
                                                   SkIntToScalar(360));

        SkMatrix saveM = *fMatrixRefs[3];
        SkScalar c = SkIntToScalar(50);
        fMatrixRefs[3]->preRotate(angle, c, c);
        
        const SkScalar dx = 350;
        const SkScalar dy = 500;
        const int N = 1;
        for (int v = -N; v <= N; v++) {
            for (int h = -N; h <= N; h++) {
                SkAutoCanvasRestore acr(canvas, true);
                canvas->translate(h * dx, v * dy);
        
        SkMatrix matrix;
     
        SkGroupShape* gs = new SkGroupShape;
        SkAutoUnref aur(gs);
        gs->appendShape(&fGroup);
        matrix.setScale(-SK_Scalar1, SK_Scalar1);
        matrix.postTranslate(SkIntToScalar(220), SkIntToScalar(240));
        gs->appendShape(&fGroup, matrix);
        matrix.setTranslate(SkIntToScalar(240), 0);
        matrix.preScale(SK_Scalar1*2, SK_Scalar1*2);
        gs->appendShape(&fGroup, matrix);
        
#if 1
        SkPicture* pict = new SkPicture;
        SkCanvas* cv = pict->beginRecording(1000, 1000);
        cv->scale(SK_ScalarHalf, SK_ScalarHalf);
        gs->draw(cv);
        cv->translate(SkIntToScalar(680), SkIntToScalar(480));
        cv->scale(-SK_Scalar1, SK_Scalar1);
        gs->draw(cv);
        pict->endRecording();
        
        drawpicture(canvas, *pict);
        pict->unref();
#endif

        }}

        *fMatrixRefs[3] = saveM;
        this->inval(NULL);
}
示例#16
0
void SkGlyphCache::dump() const {
    const SkTypeface* face = fScalerContext->getTypeface();
    const SkScalerContextRec& rec = fScalerContext->getRec();
    SkMatrix matrix;
    rec.getSingleMatrix(&matrix);
    matrix.preScale(SkScalarInvert(rec.fTextSize), SkScalarInvert(rec.fTextSize));
    SkString name;
    face->getFamilyName(&name);

    SkString msg;
    msg.printf("cache typeface:%x %25s:%d size:%2g [%g %g %g %g] lum:%02X devG:%d pntG:%d cntr:%d glyphs:%3d",
               face->uniqueID(), name.c_str(), face->style(), rec.fTextSize,
               matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewX],
               matrix[SkMatrix::kMSkewY], matrix[SkMatrix::kMScaleY],
               rec.fLumBits & 0xFF, rec.fDeviceGamma, rec.fPaintGamma, rec.fContrast,
               fGlyphMap.count());
    SkDebugf("%s\n", msg.c_str());
}
void LayerAndroid::updatePositions() {
    // apply the viewport to us
    SkMatrix matrix;
    if (!m_isFixed) {
        // turn our fields into a matrix.
        //
        // TODO: this should happen in the caller, and we should remove these
        // fields from our subclass
        matrix.setTranslate(m_translation.fX, m_translation.fY);
        if (m_doRotation) {
            matrix.preRotate(m_angleTransform);
        }
        matrix.preScale(m_scale.fX, m_scale.fY);
        this->setMatrix(matrix);
    }

    // now apply it to our children
    int count = this->countChildren();
    for (int i = 0; i < count; i++) {
        this->getChild(i)->updatePositions();
    }
}
SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
    fState.get()->fImage.lockPixels();

    SkMatrix finalMatrix = fState.get()->fCanvasTransform;
    finalMatrix.preConcat(fState.get()->fShaderTransform);
    SkRect surfaceBBox;
    surfaceBBox.set(fState.get()->fBBox);
    transformBBox(finalMatrix, &surfaceBBox);

    SkMatrix unflip;
    unflip.setTranslate(0, SkScalarRound(surfaceBBox.height()));
    unflip.preScale(SK_Scalar1, -SK_Scalar1);
    SkISize size = SkISize::Make(SkScalarRound(surfaceBBox.width()),
                                 SkScalarRound(surfaceBBox.height()));
    SkPDFDevice pattern(size, size, unflip);
    SkCanvas canvas(&pattern);
    canvas.translate(-surfaceBBox.fLeft, -surfaceBBox.fTop);
    finalMatrix.preTranslate(surfaceBBox.fLeft, surfaceBBox.fTop);

    const SkBitmap* image = &fState.get()->fImage;
    int width = image->width();
    int height = image->height();
    SkShader::TileMode tileModes[2];
    tileModes[0] = fState.get()->fImageTileModes[0];
    tileModes[1] = fState.get()->fImageTileModes[1];

    canvas.drawBitmap(*image, 0, 0);
    SkRect patternBBox = SkRect::MakeXYWH(-surfaceBBox.fLeft, -surfaceBBox.fTop,
                                          width, 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);
        canvas.drawBitmapMatrix(*image, xMirror);
        patternBBox.fRight += width;
    }
    if (tileModes[1] == SkShader::kMirror_TileMode) {
        SkMatrix yMirror;
        yMirror.setScale(SK_Scalar1, -SK_Scalar1);
        yMirror.postTranslate(0, 2 * height);
        canvas.drawBitmapMatrix(*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);
        canvas.drawBitmapMatrix(*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(surfaceBBox.fLeft, surfaceBBox.fTop, 0, 0);
        if (!rect.isEmpty()) {
            paint.setColor(image->getColor(0, 0));
            canvas.drawRect(rect, paint);
        }

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

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

        rect = SkRect::MakeLTRB(surfaceBBox.fLeft, height, 0,
                                surfaceBBox.fBottom);
        if (!rect.isEmpty()) {
            paint.setColor(image->getColor(0, 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, height);
        if (surfaceBBox.fLeft < 0) {
            SkBitmap left;
            SkAssertResult(image->extractSubset(&left, subset));

            SkMatrix leftMatrix;
            leftMatrix.setScale(-surfaceBBox.fLeft, 1);
            leftMatrix.postTranslate(surfaceBBox.fLeft, 0);
            canvas.drawBitmapMatrix(left, leftMatrix);

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

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

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

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

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

            SkMatrix topMatrix;
            topMatrix.setScale(SK_Scalar1, -surfaceBBox.fTop);
            topMatrix.postTranslate(0, surfaceBBox.fTop);
            canvas.drawBitmapMatrix(top, topMatrix);

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

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

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

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

    SkRefPtr<SkPDFArray> patternBBoxArray = new SkPDFArray;
    patternBBoxArray->unref();  // SkRefPtr and new both took a reference.
    patternBBoxArray->reserve(4);
    patternBBoxArray->appendScalar(patternBBox.fLeft);
    patternBBoxArray->appendScalar(patternBBox.fTop);
    patternBBoxArray->appendScalar(patternBBox.fRight);
    patternBBoxArray->appendScalar(patternBBox.fBottom);

    // Put the canvas into the pattern stream (fContent).
    SkRefPtr<SkStream> content = pattern.content();
    content->unref();  // SkRefPtr and content() both took a reference.
    pattern.getResources(&fResources);

    setData(content.get());
    insertName("Type", "Pattern");
    insertInt("PatternType", 1);
    insertInt("PaintType", 1);
    insertInt("TilingType", 1);
    insert("BBox", patternBBoxArray.get());
    insertScalar("XStep", patternBBox.width());
    insertScalar("YStep", patternBBox.height());
    insert("Resources", pattern.getResourceDict());
    insert("Matrix", SkPDFUtils::MatrixToArray(finalMatrix))->unref();

    fState.get()->fImage.unlockPixels();
}
示例#19
0
void NativeImageSkia::drawPattern(
    GraphicsContext* context,
    const FloatRect& floatSrcRect,
    const FloatSize& scale,
    const FloatPoint& phase,
    CompositeOperator compositeOp,
    const FloatRect& destRect,
    WebBlendMode blendMode,
    const IntSize& repeatSpacing) const
{
    FloatRect normSrcRect = floatSrcRect;
    normSrcRect.intersect(FloatRect(0, 0, bitmap().width(), bitmap().height()));
    if (destRect.isEmpty() || normSrcRect.isEmpty())
        return; // nothing to draw

    SkMatrix totalMatrix = context->getTotalMatrix();
    AffineTransform ctm = context->getCTM();
    SkScalar ctmScaleX = ctm.xScale();
    SkScalar ctmScaleY = ctm.yScale();
    totalMatrix.preScale(scale.width(), scale.height());

    // Figure out what size the bitmap will be in the destination. The
    // destination rect is the bounds of the pattern, we need to use the
    // matrix to see how big it will be.
    SkRect destRectTarget;
    totalMatrix.mapRect(&destRectTarget, normSrcRect);

    float destBitmapWidth = SkScalarToFloat(destRectTarget.width());
    float destBitmapHeight = SkScalarToFloat(destRectTarget.height());

    bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap());

    // Compute the resampling mode.
    InterpolationQuality resampling;
    if (context->isAccelerated())
        resampling = InterpolationLow;
    else if (isLazyDecoded)
        resampling = InterpolationHigh;
    else
        resampling = computeInterpolationQuality(totalMatrix, normSrcRect.width(), normSrcRect.height(), destBitmapWidth, destBitmapHeight, isDataComplete());
    resampling = limitInterpolationQuality(context, resampling);

    SkMatrix localMatrix;
    // We also need to translate it such that the origin of the pattern is the
    // origin of the destination rect, which is what WebKit expects. Skia uses
    // the coordinate system origin as the base for the pattern. If WebKit wants
    // a shifted image, it will shift it from there using the localMatrix.
    const float adjustedX = phase.x() + normSrcRect.x() * scale.width();
    const float adjustedY = phase.y() + normSrcRect.y() * scale.height();
    localMatrix.setTranslate(SkFloatToScalar(adjustedX), SkFloatToScalar(adjustedY));

    RefPtr<SkShader> shader;
    SkFilterQuality filterLevel = static_cast<SkFilterQuality>(resampling);

    // Bicubic filter is only applied to defer-decoded images, see
    // NativeImageSkia::draw for details.
    if (resampling == InterpolationHigh && !isLazyDecoded) {
        // Do nice resampling.
        filterLevel = kNone_SkFilterQuality;
        float scaleX = destBitmapWidth / normSrcRect.width();
        float scaleY = destBitmapHeight / normSrcRect.height();
        SkRect scaledSrcRect;

        // Since we are resizing the bitmap, we need to remove the scale
        // applied to the pixels in the bitmap shader. This means we need
        // CTM * localMatrix to have identity scale. Since we
        // can't modify CTM (or the rectangle will be drawn in the wrong
        // place), we must set localMatrix's scale to the inverse of
        // CTM scale.
        localMatrix.preScale(ctmScaleX ? 1 / ctmScaleX : 1, ctmScaleY ? 1 / ctmScaleY : 1);

        // The image fragment generated here is not exactly what is
        // requested. The scale factor used is approximated and image
        // fragment is slightly larger to align to integer
        // boundaries.
        SkBitmap resampled = extractScaledImageFragment(normSrcRect, scaleX, scaleY, &scaledSrcRect);
        if (repeatSpacing.isZero()) {
            shader = adoptRef(SkShader::CreateBitmapShader(resampled, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
        } else {
            shader = adoptRef(SkShader::CreateBitmapShader(
                createBitmapWithSpace(resampled, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY),
                SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
        }
    } else {
        // Because no resizing occurred, the shader transform should be
        // set to the pattern's transform, which just includes scale.
        localMatrix.preScale(scale.width(), scale.height());

        // No need to resample before drawing.
        SkBitmap srcSubset;
        bitmap().extractSubset(&srcSubset, enclosingIntRect(normSrcRect));
        if (repeatSpacing.isZero()) {
            shader = adoptRef(SkShader::CreateBitmapShader(srcSubset, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
        } else {
            shader = adoptRef(SkShader::CreateBitmapShader(
                createBitmapWithSpace(srcSubset, repeatSpacing.width() * ctmScaleX, repeatSpacing.height() * ctmScaleY),
                SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix));
        }
    }

    SkPaint paint;
    paint.setShader(shader.get());
    paint.setXfermodeMode(WebCoreCompositeToSkiaComposite(compositeOp, blendMode));
    paint.setColorFilter(context->colorFilter());
    paint.setFilterQuality(filterLevel);
    context->drawRect(destRect, paint);
}
示例#20
0
static int pathsDrawTheSame(const SkPath& one, const SkPath& two,
        SkBitmap& bits, SkPath& scaledOne, SkPath& scaledTwo, int& error2x2) {
    const int bitWidth = 64;
    const int bitHeight = 64;
    if (bits.width() == 0) {
        bits.setConfig(SkBitmap::kARGB_8888_Config, bitWidth * 2, bitHeight);
        bits.allocPixels();
    }

    SkRect larger = one.getBounds();
    larger.join(two.getBounds());
    SkScalar largerWidth = larger.width();
    if (largerWidth < 4) {
        largerWidth = 4;
    }
    SkScalar largerHeight = larger.height();
    if (largerHeight < 4) {
        largerHeight = 4;
    }
    SkScalar hScale = (bitWidth - 2) / largerWidth;
    SkScalar vScale = (bitHeight - 2) / largerHeight;
    SkMatrix scale;
    scale.reset();
    scale.preScale(hScale, vScale);
    one.transform(scale, &scaledOne);
    two.transform(scale, &scaledTwo);
    const SkRect& bounds1 = scaledOne.getBounds();

    SkCanvas canvas(bits);
    canvas.drawColor(SK_ColorWHITE);
    SkPaint paint;
    canvas.save();
    canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
    canvas.drawPath(scaledOne, paint);
    canvas.restore();
    canvas.save();
    canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
    canvas.drawPath(scaledTwo, paint);
    canvas.restore();
    int errors2 = 0;
    int errors = 0;
    for (int y = 0; y < bitHeight - 1; ++y) {
        uint32_t* addr1 = bits.getAddr32(0, y);
        uint32_t* addr2 = bits.getAddr32(0, y + 1);
        uint32_t* addr3 = bits.getAddr32(bitWidth, y);
        uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1);
        for (int x = 0; x < bitWidth - 1; ++x) {
            // count 2x2 blocks
            bool err = addr1[x] != addr3[x];
            if (err) {
                errors2 += addr1[x + 1] != addr3[x + 1]
                        && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
                errors++;
            }
        }
    }
    if (errors2 >= 6 || errors > 160) {
        SkDebugf("%s errors2=%d errors=%d\n", __FUNCTION__, errors2, errors);
    }
    error2x2 = errors2;
    return errors;
}
示例#21
0
    void onDraw(int loops, SkCanvas* canvas) override {
        SkRandom scaleRand;
        SkRandom transRand;
        SkRandom rotRand;

        int width, height;
        if (fUseAtlas) {
            width = kAtlasCellWidth;
            height = kAtlasCellHeight;
        } else {
            width = kCheckerboardWidth;
            height = kCheckerboardHeight;
        }

        SkPaint clearPaint;
        clearPaint.setColor(0xFF000000);
        clearPaint.setAntiAlias(true);

        SkISize size = canvas->getDeviceSize();

        SkScalar maxTransX, maxTransY;

        if (kScale_Type == fType) {
            maxTransX = size.fWidth  - (1.5f * width);
            maxTransY = size.fHeight - (1.5f * height);
        } else if (kTranslate_Type == fType) {
            maxTransX = SkIntToScalar(size.fWidth  - width);
            maxTransY = SkIntToScalar(size.fHeight - height);
        } else {
            SkASSERT(kRotate_Type == fType);
            // Yes, some rotations will be off the top and left sides
            maxTransX = size.fWidth  - SK_ScalarSqrt2 * height;
            maxTransY = size.fHeight - SK_ScalarSqrt2 * height;
        }

        SkMatrix mat;
        SkRect dst = { 0, 0, SkIntToScalar(width), SkIntToScalar(height) };
        SkRect clearRect = { -1.0f, -1.0f, width+1.0f, height+1.0f };
        SkPoint verts[4] = { // for drawVertices path
            { 0, 0 },
            { 0, SkIntToScalar(height) },
            { SkIntToScalar(width), SkIntToScalar(height) },
            { SkIntToScalar(width), 0 }
        };
        uint16_t indices[6] = { 0, 1, 2, 0, 2, 3 };

        SkPaint p;
        p.setColor(0xFF000000);
        p.setFilterQuality(kLow_SkFilterQuality);

        SkPaint p2;         // for drawVertices path
        p2.setColor(0xFF000000);
        p2.setFilterQuality(kLow_SkFilterQuality);
        p2.setShader(SkShader::MakeBitmapShader(fAtlas,
                                                SkShader::kClamp_TileMode,
                                                SkShader::kClamp_TileMode));

        for (int i = 0; i < loops; ++i, ++fNumSaved) {
            if (0 == i % kNumBeforeClear) {
                if (kPartial_Clear == fClear) {
                    for (int j = 0; j < fNumSaved; ++j) {
                        canvas->setMatrix(SkMatrix::I());
                        mat.setTranslate(fSaved[j][0], fSaved[j][1]);

                        if (kScale_Type == fType) {
                            mat.preScale(fSaved[j][2], fSaved[j][2]);
                        } else if (kRotate_Type == fType) {
                            mat.preRotate(fSaved[j][2]);
                        }

                        canvas->concat(mat);
                        canvas->drawRect(clearRect, clearPaint);
                    }
                } else {
                    canvas->clear(0xFF000000);
                }

                fNumSaved = 0;
            }

            SkASSERT(fNumSaved < kNumBeforeClear);

            canvas->setMatrix(SkMatrix::I());

            fSaved[fNumSaved][0] = transRand.nextRangeScalar(0.0f, maxTransX);
            fSaved[fNumSaved][1] = transRand.nextRangeScalar(0.0f, maxTransY);
            if (fAligned) {
                // make the translations integer aligned
                fSaved[fNumSaved][0] = SkScalarFloorToScalar(fSaved[fNumSaved][0]);
                fSaved[fNumSaved][1] = SkScalarFloorToScalar(fSaved[fNumSaved][1]);
            }

            mat.setTranslate(fSaved[fNumSaved][0], fSaved[fNumSaved][1]);

            if (kScale_Type == fType) {
                fSaved[fNumSaved][2] = scaleRand.nextRangeScalar(0.5f, 1.5f);
                mat.preScale(fSaved[fNumSaved][2], fSaved[fNumSaved][2]);
            } else if (kRotate_Type == fType) {
                fSaved[fNumSaved][2] = rotRand.nextRangeScalar(0.0f, 360.0f);
                mat.preRotate(fSaved[fNumSaved][2]);
            }

            canvas->concat(mat);
            if (fUseAtlas) {
                const int curCell = i % (kNumAtlasedX * kNumAtlasedY);
                SkIRect src = fAtlasRects[curCell % (kNumAtlasedX)][curCell / (kNumAtlasedX)];

                if (fUseDrawVertices) {
                    SkPoint uvs[4] = {
                        { SkIntToScalar(src.fLeft),  SkIntToScalar(src.fBottom) },
                        { SkIntToScalar(src.fLeft),  SkIntToScalar(src.fTop) },
                        { SkIntToScalar(src.fRight), SkIntToScalar(src.fTop) },
                        { SkIntToScalar(src.fRight), SkIntToScalar(src.fBottom) },
                    };
                    canvas->drawVertices(SkCanvas::kTriangles_VertexMode,
                                         4, verts, uvs, nullptr, nullptr,
                                         indices, 6, p2);
                } else {
                    canvas->drawBitmapRect(fAtlas, src, dst, &p,
                                           SkCanvas::kFast_SrcRectConstraint);
                }
            } else {
                canvas->drawBitmapRect(fCheckerboard, dst, &p);
            }
        }
    }
示例#22
0
 static void preScale__FF(JNIEnv* env, jobject clazz, jlong objHandle, jfloat sx, jfloat sy) {
     SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
     obj->preScale(sx, sy);
 }
示例#23
0
 virtual void performTest() {
     SkMatrix m;
     m = fM0; m.preScale(fSX, fSY);
     m = fM1; m.preScale(fSX, fSY);
     m = fM2; m.preScale(fSX, fSY);
 }
示例#24
0
    void onDraw(SkCanvas* canvas) override {
        fShader = gBleedRec[fBT].fShaderMaker();

        canvas->clear(SK_ColorGRAY);
        SkTDArray<SkMatrix> matrices;
        // Draw with identity
        *matrices.append() = SkMatrix::I();

        // Draw with rotation and scale down in x, up in y.
        SkMatrix m;
        constexpr SkScalar kBottom = SkIntToScalar(kRow4Y + kBlockSize + kBlockSpacing);
        m.setTranslate(0, kBottom);
        m.preRotate(15.f, 0, kBottom + kBlockSpacing);
        m.preScale(0.71f, 1.22f);
        *matrices.append() = m;

        // Align the next set with the middle of the previous in y, translated to the right in x.
        SkPoint corners[] = {{0, 0}, { 0, kBottom }, { kWidth, kBottom }, {kWidth, 0} };
        matrices[matrices.count()-1].mapPoints(corners, 4);
        SkScalar y = (corners[0].fY + corners[1].fY + corners[2].fY + corners[3].fY) / 4;
        SkScalar x = SkTMax(SkTMax(corners[0].fX, corners[1].fX),
                            SkTMax(corners[2].fX, corners[3].fX));
        m.setTranslate(x, y);
        m.preScale(0.2f, 0.2f);
        *matrices.append() = m;

        SkScalar maxX = 0;
        for (int antiAlias = 0; antiAlias < 2; ++antiAlias) {
            canvas->save();
            canvas->translate(maxX, 0);
            for (int m = 0; m < matrices.count(); ++m) {
                canvas->save();
                canvas->concat(matrices[m]);
                bool aa = SkToBool(antiAlias);

                // First draw a column with no bleeding and no filtering
                this->drawCase1(canvas, kCol0X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
                this->drawCase2(canvas, kCol0X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
                this->drawCase3(canvas, kCol0X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
                this->drawCase4(canvas, kCol0X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);
                this->drawCase5(canvas, kCol0X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kNone_SkFilterQuality);

                // Then draw a column with no bleeding and low filtering
                this->drawCase1(canvas, kCol1X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
                this->drawCase2(canvas, kCol1X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
                this->drawCase3(canvas, kCol1X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
                this->drawCase4(canvas, kCol1X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);
                this->drawCase5(canvas, kCol1X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kLow_SkFilterQuality);

                // Then draw a column with no bleeding and high filtering
                this->drawCase1(canvas, kCol2X, kRow0Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
                this->drawCase2(canvas, kCol2X, kRow1Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
                this->drawCase3(canvas, kCol2X, kRow2Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
                this->drawCase4(canvas, kCol2X, kRow3Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);
                this->drawCase5(canvas, kCol2X, kRow4Y, aa, SkCanvas::kStrict_SrcRectConstraint, kHigh_SkFilterQuality);

                // Then draw a column with bleeding and no filtering (bleed should have no effect w/out blur)
                this->drawCase1(canvas, kCol3X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
                this->drawCase2(canvas, kCol3X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
                this->drawCase3(canvas, kCol3X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
                this->drawCase4(canvas, kCol3X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);
                this->drawCase5(canvas, kCol3X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kNone_SkFilterQuality);

                // Then draw a column with bleeding and low filtering
                this->drawCase1(canvas, kCol4X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
                this->drawCase2(canvas, kCol4X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
                this->drawCase3(canvas, kCol4X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
                this->drawCase4(canvas, kCol4X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);
                this->drawCase5(canvas, kCol4X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kLow_SkFilterQuality);

                // Finally draw a column with bleeding and high filtering
                this->drawCase1(canvas, kCol5X, kRow0Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
                this->drawCase2(canvas, kCol5X, kRow1Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
                this->drawCase3(canvas, kCol5X, kRow2Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
                this->drawCase4(canvas, kCol5X, kRow3Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);
                this->drawCase5(canvas, kCol5X, kRow4Y, aa, SkCanvas::kFast_SrcRectConstraint, kHigh_SkFilterQuality);

                SkPoint corners[] = { { 0, 0 },{ 0, kBottom },{ kWidth, kBottom },{ kWidth, 0 } };
                matrices[m].mapPoints(corners, 4);
                SkScalar x = kBlockSize + SkTMax(SkTMax(corners[0].fX, corners[1].fX),
                                                 SkTMax(corners[2].fX, corners[3].fX));
                maxX = SkTMax(maxX, x);
                canvas->restore();
            }
            canvas->restore();
        }
    }
示例#25
0
void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
{
    SkASSERT(fScaledFont != nullptr);

    glyph->zeroMetrics();

    CairoLockedFTFace faceLock(fScaledFont);
    FT_Face face = faceLock.getFace();

    FT_Error err = FT_Load_Glyph( face, glyph->getGlyphID(), fLoadGlyphFlags );
    if (err != 0) {
        return;
    }

    prepareGlyph(face->glyph);

    switch (face->glyph->format) {
    case FT_GLYPH_FORMAT_OUTLINE:
        if (!face->glyph->outline.n_contours) {
            break;
        }

        FT_BBox bbox;
        FT_Outline_Get_CBox(&face->glyph->outline, &bbox);
        bbox.xMin &= ~63;
        bbox.yMin &= ~63;
        bbox.xMax = (bbox.xMax + 63) & ~63;
        bbox.yMax = (bbox.yMax + 63) & ~63;
        glyph->fWidth  = SkToU16(SkFDot6Floor(bbox.xMax - bbox.xMin));
        glyph->fHeight = SkToU16(SkFDot6Floor(bbox.yMax - bbox.yMin));
        glyph->fTop    = -SkToS16(SkFDot6Floor(bbox.yMax));
        glyph->fLeft   = SkToS16(SkFDot6Floor(bbox.xMin));

        if (isLCD(fRec) &&
            gSetLcdFilter &&
            (fLcdFilter == FT_LCD_FILTER_DEFAULT ||
             fLcdFilter == FT_LCD_FILTER_LIGHT)) {
            if (fRec.fFlags & kLCD_Vertical_Flag) {
                glyph->fTop -= 1;
                glyph->fHeight += 2;
            } else {
                glyph->fLeft -= 1;
                glyph->fWidth += 2;
            }
        }
        break;
    case FT_GLYPH_FORMAT_BITMAP:
#ifdef FT_LOAD_COLOR
        if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
            glyph->fMaskFormat = SkMask::kARGB32_Format;
        }
#endif

        if (isLCD(fRec)) {
            fRec.fMaskFormat = SkMask::kA8_Format;
        }

        if (fHaveShape) {
            // Apply the shape matrix to the glyph's bounding box.
            SkMatrix matrix;
            fRec.getSingleMatrix(&matrix);
            matrix.preScale(SkScalarInvert(fScaleX), SkScalarInvert(fScaleY));
            SkRect srcRect = SkRect::MakeXYWH(
                SkIntToScalar(face->glyph->bitmap_left),
                -SkIntToScalar(face->glyph->bitmap_top),
                SkIntToScalar(face->glyph->bitmap.width),
                SkIntToScalar(face->glyph->bitmap.rows));
            SkRect destRect;
            matrix.mapRect(&destRect, srcRect);
            SkIRect glyphRect = destRect.roundOut();
            glyph->fWidth  = SkToU16(glyphRect.width());
            glyph->fHeight = SkToU16(glyphRect.height());
            glyph->fTop    = SkToS16(SkScalarRoundToInt(destRect.fTop));
            glyph->fLeft   = SkToS16(SkScalarRoundToInt(destRect.fLeft));
        } else {
            glyph->fWidth  = SkToU16(face->glyph->bitmap.width);
            glyph->fHeight = SkToU16(face->glyph->bitmap.rows);
            glyph->fTop    = -SkToS16(face->glyph->bitmap_top);
            glyph->fLeft   = SkToS16(face->glyph->bitmap_left);
        }
        break;
    default:
        SkDEBUGFAIL("unknown glyph format");
        return;
    }

    if (fRec.fFlags & SkScalerContext::kVertical_Flag) {
        glyph->fAdvanceX = -SkFDot6ToFloat(face->glyph->advance.x);
        glyph->fAdvanceY = SkFDot6ToFloat(face->glyph->advance.y);
    } else {
        glyph->fAdvanceX = SkFDot6ToFloat(face->glyph->advance.x);
        glyph->fAdvanceY = -SkFDot6ToFloat(face->glyph->advance.y);
    }
}
int SkBuildQuadArc(const SkVector& uStart, const SkVector& uStop,
                   SkRotationDirection dir, const SkMatrix* userMatrix,
                   SkPoint quadPoints[])
{
    // rotate by x,y so that uStart is (1.0)
    SkScalar x = SkPoint::DotProduct(uStart, uStop);
    SkScalar y = SkPoint::CrossProduct(uStart, uStop);

    SkScalar absX = SkScalarAbs(x);
    SkScalar absY = SkScalarAbs(y);

    int pointCount;

    // check for (effectively) coincident vectors
    // this can happen if our angle is nearly 0 or nearly 180 (y == 0)
    // ... we use the dot-prod to distinguish between 0 and 180 (x > 0)
    if (absY <= SK_ScalarNearlyZero && x > 0 &&
        ((y >= 0 && kCW_SkRotationDirection == dir) ||
         (y <= 0 && kCCW_SkRotationDirection == dir))) {
            
        // just return the start-point
        quadPoints[0].set(SK_Scalar1, 0);
        pointCount = 1;
    } else {
        if (dir == kCCW_SkRotationDirection)
            y = -y;

        // what octant (quadratic curve) is [xy] in?
        int oct = 0;
        bool sameSign = true;

        if (0 == y)
        {
            oct = 4;        // 180
            SkASSERT(SkScalarAbs(x + SK_Scalar1) <= SK_ScalarNearlyZero);
        }
        else if (0 == x)
        {
            SkASSERT(absY - SK_Scalar1 <= SK_ScalarNearlyZero);
            if (y > 0)
                oct = 2;    // 90
            else
                oct = 6;    // 270
        }
        else
        {
            if (y < 0)
                oct += 4;
            if ((x < 0) != (y < 0))
            {
                oct += 2;
                sameSign = false;
            }
            if ((absX < absY) == sameSign)
                oct += 1;
        }

        int wholeCount = oct << 1;
        memcpy(quadPoints, gQuadCirclePts, (wholeCount + 1) * sizeof(SkPoint));

        const SkPoint* arc = &gQuadCirclePts[wholeCount];
        if (quad_pt2OffCurve(arc, x, y, &quadPoints[wholeCount + 1]))
        {
            quadPoints[wholeCount + 2].set(x, y);
            wholeCount += 2;
        }
        pointCount = wholeCount + 1;
    }

    // now handle counter-clockwise and the initial unitStart rotation
    SkMatrix    matrix;
    matrix.setSinCos(uStart.fY, uStart.fX);
    if (dir == kCCW_SkRotationDirection) {
        matrix.preScale(SK_Scalar1, -SK_Scalar1);
    }
    if (userMatrix) {
        matrix.postConcat(*userMatrix);
    }
    matrix.mapPoints(quadPoints, pointCount);
    return pointCount;
}
示例#27
0
SkPDFImageShader::SkPDFImageShader(SkPDFShader::State* state) : fState(state) {
    fState.get()->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 = fState.get()->fCanvasTransform;
    finalMatrix.preConcat(fState.get()->fShaderTransform);
    SkRect deviceBounds;
    deviceBounds.set(fState.get()->fBBox);
    if (!inverseTransformBBox(finalMatrix, &deviceBounds)) {
        return;
    }

    const SkBitmap* image = &fState.get()->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] = fState.get()->fImageTileModes[0];
    tileModes[1] = fState.get()->fImageTileModes[1];
    if (tileModes[0] != SkShader::kClamp_TileMode ||
            tileModes[1] != SkShader::kClamp_TileMode) {
        deviceBounds.join(bitmapBounds);
    }

    SkMatrix unflip;
    unflip.setTranslate(0, SkScalarRoundToScalar(deviceBounds.height()));
    unflip.preScale(SK_Scalar1, -SK_Scalar1);
    SkISize size = SkISize::Make(SkScalarRound(deviceBounds.width()),
                                 SkScalarRound(deviceBounds.height()));
    SkPDFDevice pattern(size, size, unflip);
    SkCanvas canvas(&pattern);

    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);
        canvas.drawBitmapMatrix(*image, xMirror);
        patternBBox.fRight += width;
    }
    if (tileModes[1] == SkShader::kMirror_TileMode) {
        SkMatrix yMirror;
        yMirror.setScale(SK_Scalar1, -SK_Scalar1);
        yMirror.postTranslate(0, 2 * height);
        canvas.drawBitmapMatrix(*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);
        canvas.drawBitmapMatrix(*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);
            canvas.drawBitmapMatrix(left, leftMatrix);

            if (tileModes[1] == SkShader::kMirror_TileMode) {
                leftMatrix.postScale(SK_Scalar1, -SK_Scalar1);
                leftMatrix.postTranslate(0, 2 * height);
                canvas.drawBitmapMatrix(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);
            canvas.drawBitmapMatrix(right, rightMatrix);

            if (tileModes[1] == SkShader::kMirror_TileMode) {
                rightMatrix.postScale(SK_Scalar1, -SK_Scalar1);
                rightMatrix.postTranslate(0, 2 * height);
                canvas.drawBitmapMatrix(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());
            canvas.drawBitmapMatrix(top, topMatrix);

            if (tileModes[0] == SkShader::kMirror_TileMode) {
                topMatrix.postScale(-1, 1);
                topMatrix.postTranslate(2 * width, 0);
                canvas.drawBitmapMatrix(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);
            canvas.drawBitmapMatrix(bottom, bottomMatrix);

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

    // Put the canvas into the pattern stream (fContent).
    SkAutoTUnref<SkStream> content(pattern.content());
    setData(content.get());
    SkPDFResourceDict* resourceDict = pattern.getResourceDict();
    resourceDict->getReferencedResources(fResources, &fResources, false);

    populate_tiling_pattern_dict(this, patternBBox,
                                 pattern.getResourceDict(), finalMatrix);

    fState.get()->fImage.unlockPixels();
}
示例#28
0
bool SVGPaintServerGradient::setup(GraphicsContext*& context, 
    const RenderObject* object, 
    SVGPaintTargetType type, 
    bool isPaintingText) const
{
    m_ownerElement->buildGradient();

    RenderStyle* style = object->style();
    bool isFilled = 
        (type & ApplyToFillTargetType) && 
         style->svgStyle()->hasFill();
    bool isStroked = 
        (type & ApplyToStrokeTargetType) && 
         style->svgStyle()->hasStroke();

    if(!gradientStops().size())
        return false;

    if(gradientStops().size()==1) {
        context->setFillColor(gradientStops()[0].second);
        return true;
    }

    // Create a gradient builder helper to generate the data 
    // we'll need to provide Skia
    SkiaGradientBuilder builder(gradientStops(), 
        isFilled ? style->svgStyle()->fillOpacity() : 
                   style->svgStyle()->strokeOpacity());

    SkShader::TileMode tile_mode;

    // Convert SVG spread modes to Skia tile modes
    switch(spreadMethod())
    {
    default:
    case SPREADMETHOD_PAD:     
        tile_mode = SkShader::kClamp_TileMode; break;
    case SPREADMETHOD_REFLECT: 
        tile_mode = SkShader::kMirror_TileMode; break;
    case SPREADMETHOD_REPEAT:  
        tile_mode = SkShader::kRepeat_TileMode; break;
    }

    SkShader* shader = NULL;

    SkMatrix matrix;

    // Calculate a matrix to transform a gradient to fit the bounding box
    if (boundingBoxMode()) {
        matrix.reset();
        SkRect rc = context->getBoundingBoxForCurrentPath(true);

        matrix.preTranslate(rc.fLeft, rc.fTop);
        matrix.preScale(rc.width(), rc.height());
        matrix.preConcat(gradientTransform());
    } else
        matrix = gradientTransform();

    if (this->type() == LinearGradientPaintServer) {
        const SVGPaintServerLinearGradient* linear = 
            static_cast<const SVGPaintServerLinearGradient*>(this);

        SkPoint pts[2];

        pts[0].fX = linear->gradientStart().x();
        pts[0].fY = linear->gradientStart().y();
        pts[1].fX = linear->gradientEnd().x();
        pts[1].fY = linear->gradientEnd().y();

        shader = SkGradientShader::CreateLinear(pts, 
            builder.colors(), builder.pos(), builder.count(), tile_mode);
    } else if (this->type() == RadialGradientPaintServer) {
        const SVGPaintServerRadialGradient* radial = 
            static_cast<const SVGPaintServerRadialGradient*>(this);

        SkPoint center;
        SkScalar radius;

        center.fX = radial->gradientCenter().x();
        center.fY = radial->gradientCenter().y();
        radius = radial->gradientRadius();

        shader = SkGradientShader::CreateRadial(
            center, radius, builder.colors(), builder.pos(), 
            builder.count(), tile_mode);

    } else {
        return false;
    }

    if (isPaintingText) {
        if (isFilled) {
            context->setTextDrawingMode(cTextFill);
        }

        if (isStroked) {
            context->setTextDrawingMode(cTextStroke);
        }
    }

    if (isStroked) {
        applyStrokeStyleToContext(context, style, object);
    }

    if (shader) {
        shader->setLocalMatrix(matrix);
        context->platformContext()->setGradient(shader);

        return true;
    }

    return false;
}
示例#29
0
sk_sp<SkShader> Gradient::createShader(const SkMatrix& localMatrix) {
  sortStopsIfNecessary();
  ASSERT(m_stopsSorted);

  size_t countUsed = totalStopsNeeded(m_stops.data(), m_stops.size());
  ASSERT(countUsed >= 2);
  ASSERT(countUsed >= m_stops.size());

  ColorStopOffsetVector pos(countUsed);
  ColorStopColorVector colors(countUsed);
  fillStops(m_stops.data(), m_stops.size(), pos, colors);

  SkShader::TileMode tile = SkShader::kClamp_TileMode;
  switch (m_spreadMethod) {
    case SpreadMethodReflect:
      tile = SkShader::kMirror_TileMode;
      break;
    case SpreadMethodRepeat:
      tile = SkShader::kRepeat_TileMode;
      break;
    case SpreadMethodPad:
      tile = SkShader::kClamp_TileMode;
      break;
  }

  sk_sp<SkShader> shader;
  uint32_t shouldDrawInPMColorSpace =
      m_drawInPMColorSpace ? SkGradientShader::kInterpolateColorsInPremul_Flag
                           : 0;
  if (m_radial) {
    SkMatrix adjustedLocalMatrix = localMatrix;

    if (m_aspectRatio != 1) {
      // CSS3 elliptical gradients: apply the elliptical scaling at the
      // gradient center point.
      adjustedLocalMatrix.preTranslate(m_p0.x(), m_p0.y());
      adjustedLocalMatrix.preScale(1, 1 / m_aspectRatio);
      adjustedLocalMatrix.preTranslate(-m_p0.x(), -m_p0.y());
      ASSERT(m_p0 == m_p1);
    }

    // Since the two-point radial gradient is slower than the plain radial,
    // only use it if we have to.
    if (m_p0 == m_p1 && m_r0 <= 0.0f) {
      shader = SkGradientShader::MakeRadial(
          m_p1.data(), m_r1, colors.data(), pos.data(),
          static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace,
          &adjustedLocalMatrix);
    } else {
      // The radii we give to Skia must be positive. If we're given a
      // negative radius, ask for zero instead.
      SkScalar radius0 = m_r0 >= 0.0f ? WebCoreFloatToSkScalar(m_r0) : 0;
      SkScalar radius1 = m_r1 >= 0.0f ? WebCoreFloatToSkScalar(m_r1) : 0;
      shader = SkGradientShader::MakeTwoPointConical(
          m_p0.data(), radius0, m_p1.data(), radius1, colors.data(), pos.data(),
          static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace,
          &adjustedLocalMatrix);
    }
  } else {
    SkPoint pts[2] = {m_p0.data(), m_p1.data()};
    shader = SkGradientShader::MakeLinear(
        pts, colors.data(), pos.data(), static_cast<int>(countUsed), tile,
        shouldDrawInPMColorSpace, &localMatrix);
  }

  if (!shader) {
    // use last color, since our "geometry" was degenerate (e.g. radius==0)
    shader = SkShader::MakeColorShader(colors[countUsed - 1]);
  }

  return shader;
}
示例#30
0
 void performTest() override {
     SkMatrix m;
     m = fM0; m.preScale(fSX, fSY);
     m = fM1; m.preScale(fSX, fSY);
     m = fM2; m.preScale(fSX, fSY);
 }