Ejemplo n.º 1
0
bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& bounds,
                      SkRegion::Op op, bool doAA) {
    AUTO_RASTERCLIP_VALIDATE(*this);
    SkRect devRect;

    if (fForceConservativeRects) {
        SkIRect ir;
        switch (mutate_conservative_op(&op, false)) {
            case kDoNothing_MutateResult:
                return !this->isEmpty();
            case kReplaceClippedAgainstGlobalBounds_MutateResult:
                ir = bounds;
                break;
            case kContinue_MutateResult:
                matrix.mapRect(&devRect, localRect);
                ir = devRect.roundOut();
                break;
        }
        return this->op(ir, op);
    }
    const bool isScaleTrans = matrix.isScaleTranslate();
    if (!isScaleTrans) {
        SkPath path;
        path.addRect(localRect);
        path.setIsVolatile(true);
        return this->op(path, matrix, bounds, op, doAA);
    }

    matrix.mapRect(&devRect, localRect);

    if (fIsBW && doAA) {
        // check that the rect really needs aa, or is it close enought to
        // integer boundaries that we can just treat it as a BW rect?
        if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
            nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
            doAA = false;
        }
    }

    if (fIsBW && !doAA) {
        SkIRect ir;
        devRect.round(&ir);
        (void)fBW.op(ir, op);
    } else {
        if (fIsBW) {
            this->convertToAA();
        }
        (void)fAA.op(devRect, op, doAA);
    }
    return this->updateCacheAndReturnNonEmpty();
}
Ejemplo n.º 2
0
void SkLatticeIter::mapDstScaleTranslate(const SkMatrix& matrix) {
    SkASSERT(matrix.isScaleTranslate());
    SkScalar tx = matrix.getTranslateX();
    SkScalar sx = matrix.getScaleX();
    for (int i = 0; i < fDstX.count(); i++) {
        fDstX[i] = fDstX[i] * sx + tx;
    }

    SkScalar ty = matrix.getTranslateY();
    SkScalar sy = matrix.getScaleY();
    for (int i = 0; i < fDstY.count(); i++) {
        fDstY[i] = fDstY[i] * sy + ty;
    }
}
Ejemplo n.º 3
0
static bool legacy_shader_can_handle(const SkMatrix& inv) {
    if (!inv.isScaleTranslate()) {
        return false;
    }

    // legacy code uses SkFixed 32.32, so ensure the inverse doesn't map device coordinates
    // out of range.
    const SkScalar max_dev_coord = 32767.0f;
    SkRect src;
    SkAssertResult(inv.mapRect(&src, SkRect::MakeWH(max_dev_coord, max_dev_coord)));

    // take 1/4 of max signed 32bits so we have room to subtract local values
    const SkScalar max_fixed32dot32 = SK_MaxS32 * 0.25f;
    if (!SkRect::MakeLTRB(-max_fixed32dot32, -max_fixed32dot32,
                           max_fixed32dot32, max_fixed32dot32).contains(src)) {
        return false;
    }

    // legacy shader impl should be able to handle these matrices
    return true;
}
Ejemplo n.º 4
0
// TODO just use class params
// TODO trying to figure out why lcd is so whack
sk_sp<GrGeometryProcessor> GrAtlasTextBatch::setupDfProcessor(const SkMatrix& viewMatrix,
                                                              SkColor filteredColor,
                                                              GrColor color,
                                                              GrTexture* texture) const {
    GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
    bool isLCD = this->isLCD();
    // set up any flags
    uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
    flags |= viewMatrix.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
    flags |= fUseGammaCorrectDistanceTable ? kGammaCorrect_DistanceFieldEffectFlag : 0;

    // see if we need to create a new effect
    if (isLCD) {
        flags |= kUseLCD_DistanceFieldEffectFlag;
        flags |= fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;

        GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);

        float redCorrection = fDistanceAdjustTable->getAdjustment(
            GrColorUnpackR(colorNoPreMul) >> kDistanceAdjustLumShift,
            fUseGammaCorrectDistanceTable);
        float greenCorrection = fDistanceAdjustTable->getAdjustment(
            GrColorUnpackG(colorNoPreMul) >> kDistanceAdjustLumShift,
            fUseGammaCorrectDistanceTable);
        float blueCorrection = fDistanceAdjustTable->getAdjustment(
            GrColorUnpackB(colorNoPreMul) >> kDistanceAdjustLumShift,
            fUseGammaCorrectDistanceTable);
        GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
            GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrection,
                                                                greenCorrection,
                                                                blueCorrection);

        return GrDistanceFieldLCDTextGeoProc::Make(color,
                                                   viewMatrix,
                                                   texture,
                                                   params,
                                                   widthAdjust,
                                                   flags,
                                                   this->usesLocalCoords());
    } else {
Ejemplo n.º 5
0
bool SkRasterClip::op(const SkRect& localRect, const SkMatrix& matrix, const SkIRect& devBounds,
                      SkRegion::Op op, bool doAA) {
    AUTO_RASTERCLIP_VALIDATE(*this);
    SkRect devRect;

    const bool isScaleTrans = matrix.isScaleTranslate();
    if (!isScaleTrans) {
        SkPath path;
        path.addRect(localRect);
        path.setIsVolatile(true);
        return this->op(path, matrix, devBounds, op, doAA);
    }

    matrix.mapRect(&devRect, localRect);

    if (fIsBW && doAA) {
        // check that the rect really needs aa, or is it close enought to
        // integer boundaries that we can just treat it as a BW rect?
        if (nearly_integral(devRect.fLeft) && nearly_integral(devRect.fTop) &&
            nearly_integral(devRect.fRight) && nearly_integral(devRect.fBottom)) {
            doAA = false;
        }
    }

    if (fIsBW && !doAA) {
        SkIRect ir;
        devRect.round(&ir);
        this->applyClipRestriction(op, &ir);
        (void)fBW.op(ir, op);
    } else {
        if (fIsBW) {
            this->convertToAA();
        }
        this->applyClipRestriction(op, &devRect);
        (void)fAA.op(devRect, op, doAA);
    }
    return this->updateCacheAndReturnNonEmpty();
}
Ejemplo n.º 6
0
bool SkBitmapProcInfo::init(const SkMatrix& inv, const SkPaint& paint) {
    SkASSERT(inv.isScaleTranslate());

    fPixmap.reset();
    fInvMatrix = inv;
    fFilterQuality = paint.getFilterQuality();

    fBMState = SkBitmapController::RequestBitmap(fProvider, inv, paint.getFilterQuality(), &fAlloc);

    // Note : we allow the controller to return an empty (zero-dimension) result. Should we?
    if (nullptr == fBMState || fBMState->pixmap().info().isEmpty()) {
        return false;
    }
    fPixmap = fBMState->pixmap();
    fInvMatrix = fBMState->invMatrix();
    fRealInvMatrix = fBMState->invMatrix();
    fPaintColor = paint.getColor();
    fFilterQuality = fBMState->quality();
    SkASSERT(fFilterQuality <= kLow_SkFilterQuality);
    SkASSERT(fPixmap.addr());

    bool integral_translate_only = just_trans_integral(fInvMatrix);
    if (!integral_translate_only) {
        // Most of the scanline procs deal with "unit" texture coordinates, as this
        // makes it easy to perform tiling modes (repeat = (x & 0xFFFF)). To generate
        // those, we divide the matrix by its dimensions here.
        //
        // We don't do this if we're either trivial (can ignore the matrix) or clamping
        // in both X and Y since clamping to width,height is just as easy as to 0xFFFF.

        if (fTileModeX != SkShader::kClamp_TileMode ||
            fTileModeY != SkShader::kClamp_TileMode) {
            fInvMatrix.postIDiv(fPixmap.width(), fPixmap.height());
        }

        // Now that all possible changes to the matrix have taken place, check
        // to see if we're really close to a no-scale matrix.  If so, explicitly
        // set it to be so.  Subsequent code may inspect this matrix to choose
        // a faster path in this case.

        // This code will only execute if the matrix has some scale component;
        // if it's already pure translate then we won't do this inversion.

        if (matrix_only_scale_translate(fInvMatrix)) {
            SkMatrix forward;
            if (fInvMatrix.invert(&forward) && just_trans_general(forward)) {
                fInvMatrix.setTranslate(-forward.getTranslateX(), -forward.getTranslateY());
            }
        }

        // Recompute the flag after matrix adjustments.
        integral_translate_only = just_trans_integral(fInvMatrix);
    }

    fInvType = fInvMatrix.getType();

    if (kLow_SkFilterQuality == fFilterQuality &&
        (!valid_for_filtering(fPixmap.width() | fPixmap.height()) ||
         integral_translate_only)) {
        fFilterQuality = kNone_SkFilterQuality;
    }

    return true;
}
Ejemplo n.º 7
0
bool SkScalerContext_CairoFT::computeShapeMatrix(const SkMatrix& m)
{
    // Compute a shape matrix compatible with Cairo's _compute_transform.
    // Finds major/minor scales and uses them to normalize the transform.
    double scaleX = m.getScaleX();
    double skewX = m.getSkewX();
    double skewY = m.getSkewY();
    double scaleY = m.getScaleY();
    double det = scaleX * scaleY - skewY * skewX;
    if (!std::isfinite(det)) {
        fScaleX = fRec.fTextSize * fRec.fPreScaleX;
        fScaleY = fRec.fTextSize;
        fHaveShape = false;
        return false;
    }
    double major = det != 0.0 ? hypot(scaleX, skewY) : 0.0;
    double minor = major != 0.0 ? fabs(det) / major : 0.0;
    // Limit scales to be above 1pt.
    major = SkTMax(major, 1.0);
    minor = SkTMax(minor, 1.0);

    // If the font is not scalable, then choose the best available size.
    CairoLockedFTFace faceLock(fScaledFont);
    FT_Face face = faceLock.getFace();
    if (face && !FT_IS_SCALABLE(face)) {
        double bestDist = DBL_MAX;
        FT_Int bestSize = -1;
        for (FT_Int i = 0; i < face->num_fixed_sizes; i++) {
            // Distance is positive if strike is larger than desired size,
            // or negative if smaller. If previously a found smaller strike,
            // then prefer a larger strike. Otherwise, minimize distance.
            double dist = face->available_sizes[i].y_ppem / 64.0 - minor;
            if (bestDist < 0 ? dist >= bestDist : fabs(dist) <= bestDist) {
                bestDist = dist;
                bestSize = i;
            }
        }
        if (bestSize < 0) {
            fScaleX = fRec.fTextSize * fRec.fPreScaleX;
            fScaleY = fRec.fTextSize;
            fHaveShape = false;
            return false;
        }
        major = face->available_sizes[bestSize].x_ppem / 64.0;
        minor = face->available_sizes[bestSize].y_ppem / 64.0;
        fHaveShape = true;
    } else {
        fHaveShape = !m.isScaleTranslate();
    }

    fScaleX = SkDoubleToScalar(major);
    fScaleY = SkDoubleToScalar(minor);

    if (fHaveShape) {
        // Normalize the transform and convert to fixed-point.
        double invScaleX = 65536.0 / major;
        double invScaleY = 65536.0 / minor;
        fShapeMatrix.xx = (FT_Fixed)(scaleX * invScaleX);
        fShapeMatrix.yx = -(FT_Fixed)(skewY * invScaleX);
        fShapeMatrix.xy = -(FT_Fixed)(skewX * invScaleY);
        fShapeMatrix.yy = (FT_Fixed)(scaleY * invScaleY);
    }
    return true;
}
void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer,
                                          const SkRect& clippedSrcRect,
                                          const SkRect& clippedDstRect,
                                          SkCanvas::SrcRectConstraint constraint,
                                          const SkMatrix& viewMatrix,
                                          const SkMatrix& srcToDstMatrix,
                                          const GrClip& clip,
                                          const SkPaint& paint) {
    // Specifying the texture coords as local coordinates is an attempt to enable more GrDrawOp
    // combining by not baking anything about the srcRect, dstRect, or viewMatrix, into the texture
    // FP. In the future this should be an opaque optimization enabled by the combination of
    // GrDrawOp/GP and FP.
    const SkMaskFilter* mf = paint.getMaskFilter();
    // The shader expects proper local coords, so we can't replace local coords with texture coords
    // if the shader will be used. If we have a mask filter we will change the underlying geometry
    // that is rendered.
    bool canUseTextureCoordsAsLocalCoords = !use_shader(producer->isAlphaOnly(), paint) && !mf;

    bool doBicubic;
    GrSamplerParams::FilterMode fm =
        GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, srcToDstMatrix,
                                        &doBicubic);
    const GrSamplerParams::FilterMode* filterMode = doBicubic ? nullptr : &fm;

    GrTextureProducer::FilterConstraint constraintMode;
    if (SkCanvas::kFast_SrcRectConstraint == constraint) {
        constraintMode = GrTextureAdjuster::kNo_FilterConstraint;
    } else {
        constraintMode = GrTextureAdjuster::kYes_FilterConstraint;
    }

    // If we have to outset for AA then we will generate texture coords outside the src rect. The
    // same happens for any mask filter that extends the bounds rendered in the dst.
    // This is conservative as a mask filter does not have to expand the bounds rendered.
    bool coordsAllInsideSrcRect = !paint.isAntiAlias() && !mf;

    // Check for optimization to drop the src rect constraint when on bilerp.
    if (filterMode && GrSamplerParams::kBilerp_FilterMode == *filterMode &&
        GrTextureAdjuster::kYes_FilterConstraint == constraintMode && coordsAllInsideSrcRect) {
        SkMatrix combinedMatrix;
        combinedMatrix.setConcat(viewMatrix, srcToDstMatrix);
        if (can_ignore_bilerp_constraint(*producer, clippedSrcRect, combinedMatrix,
                                         fRenderTargetContext->isUnifiedMultisampled())) {
            constraintMode = GrTextureAdjuster::kNo_FilterConstraint;
        }
    }

    const SkMatrix* textureMatrix;
    SkMatrix tempMatrix;
    if (canUseTextureCoordsAsLocalCoords) {
        textureMatrix = &SkMatrix::I();
    } else {
        if (!srcToDstMatrix.invert(&tempMatrix)) {
            return;
        }
        textureMatrix = &tempMatrix;
    }
    sk_sp<GrFragmentProcessor> fp(producer->createFragmentProcessor(
        *textureMatrix, clippedSrcRect, constraintMode, coordsAllInsideSrcRect, filterMode,
        fRenderTargetContext->getColorSpace()));
    if (!fp) {
        return;
    }

    GrPaint grPaint;
    if (!SkPaintToGrPaintWithTexture(fContext.get(), fRenderTargetContext.get(), paint, viewMatrix,
                                     fp, producer->isAlphaOnly(), &grPaint)) {
        return;
    }
    GrAA aa = GrBoolToAA(paint.isAntiAlias());
    if (canUseTextureCoordsAsLocalCoords) {
        fRenderTargetContext->fillRectToRect(clip, std::move(grPaint), aa, viewMatrix,
                                             clippedDstRect, clippedSrcRect);
        return;
    }

    if (!mf) {
        fRenderTargetContext->drawRect(clip, std::move(grPaint), aa, viewMatrix, clippedDstRect);
        return;
    }

    // First see if we can do the draw + mask filter direct to the dst.
    if (viewMatrix.isScaleTranslate()) {
        SkRect devClippedDstRect;
        viewMatrix.mapRectScaleTranslate(&devClippedDstRect, clippedDstRect);

        SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
        if (mf->directFilterRRectMaskGPU(fContext.get(),
                                         fRenderTargetContext.get(),
                                         std::move(grPaint),
                                         clip,
                                         viewMatrix,
                                         rec,
                                         SkRRect::MakeRect(clippedDstRect),
                                         SkRRect::MakeRect(devClippedDstRect))) {
            return;
        }
    }

    SkPath rectPath;
    rectPath.addRect(clippedDstRect);
    rectPath.setIsVolatile(true);
    GrBlurUtils::drawPathWithMaskFilter(this->context(), fRenderTargetContext.get(), this->clip(),
                                        rectPath, std::move(grPaint), aa, viewMatrix, mf,
                                        GrStyle::SimpleFill(), true);
}