예제 #1
0
SkMatrix SkPDFDevice::setTransform(const SkMatrix& m) {
    SkMatrix old = fGraphicStack[fGraphicStackIndex].fTransform;
    if (old == m)
        return old;

    if (old.getType() != SkMatrix::kIdentity_Mask) {
        SkASSERT(fGraphicStackIndex > 0);
        SkASSERT(fGraphicStack[fGraphicStackIndex - 1].fTransform.getType() ==
                 SkMatrix::kIdentity_Mask);
        SkASSERT(fGraphicStack[fGraphicStackIndex].fClip ==
                 fGraphicStack[fGraphicStackIndex - 1].fClip);
        popGS();
    }
    if (m.getType() == SkMatrix::kIdentity_Mask)
        return old;

    if (fGraphicStackIndex == 0 || fGraphicStack[fGraphicStackIndex].fClip !=
            fGraphicStack[fGraphicStackIndex - 1].fClip)
        pushGS();

    SkScalar transform[6];
    SkAssertResult(m.pdfTransform(transform));
    for (size_t i = 0; i < SK_ARRAY_COUNT(transform); i++) {
        SkPDFScalar::Append(transform[i], &fContent);
        fContent.writeText(" ");
    }
    fContent.writeText("cm\n");
    fGraphicStack[fGraphicStackIndex].fTransform = m;

    return old;
}
예제 #2
0
static void test_matrix_recttorect(skiatest::Reporter* reporter) {
    SkRect src, dst;
    SkMatrix matrix;

    src.set(0, 0, SK_Scalar1*10, SK_Scalar1*10);
    dst = src;
    matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
    REPORTER_ASSERT(reporter, SkMatrix::kIdentity_Mask == matrix.getType());
    REPORTER_ASSERT(reporter, matrix.rectStaysRect());

    dst.offset(SK_Scalar1, SK_Scalar1);
    matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
    REPORTER_ASSERT(reporter, SkMatrix::kTranslate_Mask == matrix.getType());
    REPORTER_ASSERT(reporter, matrix.rectStaysRect());

    dst.fRight += SK_Scalar1;
    matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
    REPORTER_ASSERT(reporter,
                    (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask) == matrix.getType());
    REPORTER_ASSERT(reporter, matrix.rectStaysRect());

    dst = src;
    dst.fRight = src.fRight * 2;
    matrix.setRectToRect(src, dst, SkMatrix::kFill_ScaleToFit);
    REPORTER_ASSERT(reporter, SkMatrix::kScale_Mask == matrix.getType());
    REPORTER_ASSERT(reporter, matrix.rectStaysRect());
}
예제 #3
0
void SkDeferredCanvas::Rec::setConcat(const SkMatrix& m) {
    SkASSERT(m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask));
    
    if (m.getType() <= SkMatrix::kTranslate_Mask) {
        fType = kTrans_Type;
        fData.fTranslate.set(m.getTranslateX(), m.getTranslateY());
    } else {
        fType = kScaleTrans_Type;
        fData.fScaleTrans.fScale.set(m.getScaleX(), m.getScaleY());
        fData.fScaleTrans.fTrans.set(m.getTranslateX(), m.getTranslateY());
    }
}
예제 #4
0
/**
 *  For the purposes of drawing bitmaps, if a matrix is "almost" translate
 *  go ahead and treat it as if it were, so that subsequent code can go fast.
 */
static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
    SkASSERT(matrix_only_scale_translate(matrix));

    if (matrix.getType() & SkMatrix::kScale_Mask) {
        SkRect src, dst;
        bitmap.getBounds(&src);

        // Can't call mapRect(), since that will fix up inverted rectangles,
        // e.g. when scale is negative, and we don't want to return true for
        // those.
        matrix.mapPoints(SkTCast<SkPoint*>(&dst),
                         SkTCast<const SkPoint*>(&src),
                         2);

        // Now round all 4 edges to device space, and then compare the device
        // width/height to the original. Note: we must map all 4 and subtract
        // rather than map the "width" and compare, since we care about the
        // phase (in pixel space) that any translate in the matrix might impart.
        SkIRect idst;
        dst.round(&idst);
        return idst.width() == bitmap.width() && idst.height() == bitmap.height();
    }
    // if we got here, we're either kTranslate_Mask or identity
    return true;
}
예제 #5
0
/**
 *  Determine if the matrix can be treated as integral-only-translate,
 *  for the purpose of filtering.
 */
static bool just_trans_integral(const SkMatrix& m) {
    static constexpr SkScalar tol = SK_Scalar1 / 256;

    return m.getType() <= SkMatrix::kTranslate_Mask
        && SkScalarNearlyEqual(m.getTranslateX(), SkScalarRoundToScalar(m.getTranslateX()), tol)
        && SkScalarNearlyEqual(m.getTranslateY(), SkScalarRoundToScalar(m.getTranslateY()), tol);
}
예제 #6
0
void Matrix4::load(const SkMatrix& v) {
    memset(data, 0, sizeof(data));

    data[kScaleX]     = v[SkMatrix::kMScaleX];
    data[kSkewX]      = v[SkMatrix::kMSkewX];
    data[kTranslateX] = v[SkMatrix::kMTransX];

    data[kSkewY]      = v[SkMatrix::kMSkewY];
    data[kScaleY]     = v[SkMatrix::kMScaleY];
    data[kTranslateY] = v[SkMatrix::kMTransY];

    data[kPerspective0]  = v[SkMatrix::kMPersp0];
    data[kPerspective1]  = v[SkMatrix::kMPersp1];
    data[kPerspective2]  = v[SkMatrix::kMPersp2];

    data[kScaleZ] = 1.0f;

    // NOTE: The flags are compatible between SkMatrix and this class.
    //       However, SkMatrix::getType() does not return the flag
    //       kRectStaysRect. The return value is masked with 0xF
    //       so we need the extra rectStaysRect() check
    mType = v.getType();
    if (v.rectStaysRect()) {
        mType |= kTypeRectToRect;
    }
}
예제 #7
0
bool shouldDrawAntiAliased(const GraphicsContext* context, const SkRect& destRect)
{
    if (!context->shouldAntialias())
        return false;
    const SkMatrix totalMatrix = context->getTotalMatrix();
    // Don't disable anti-aliasing if we're rotated or skewed.
    if (!totalMatrix.rectStaysRect())
        return true;
    // Disable anti-aliasing for scales or n*90 degree rotations.
    // Allow to opt out of the optimization though for "hairline" geometry
    // images - using the shouldAntialiasHairlineImages() GraphicsContext flag.
    if (!context->shouldAntialiasHairlineImages())
        return false;
    // Check if the dimensions of the destination are "small" (less than one
    // device pixel). To prevent sudden drop-outs. Since we know that
    // kRectStaysRect_Mask is set, the matrix either has scale and no skew or
    // vice versa. We can query the kAffine_Mask flag to determine which case
    // it is.
    // FIXME: This queries the CTM while drawing, which is generally
    // discouraged. Always drawing with AA can negatively impact performance
    // though - that's why it's not always on.
    SkScalar widthExpansion, heightExpansion;
    if (totalMatrix.getType() & SkMatrix::kAffine_Mask)
        widthExpansion = totalMatrix[SkMatrix::kMSkewY], heightExpansion = totalMatrix[SkMatrix::kMSkewX];
    else
        widthExpansion = totalMatrix[SkMatrix::kMScaleX], heightExpansion = totalMatrix[SkMatrix::kMScaleY];
    return destRect.width() * fabs(widthExpansion) < 1 || destRect.height() * fabs(heightExpansion) < 1;
}
예제 #8
0
template <typename T> void write_sparse_matrix(T* writer, const SkMatrix& matrix) {
    SkMatrix::TypeMask tm = matrix.getType();
    SkScalar tmp[9];
    if (tm & SkMatrix::kPerspective_Mask) {
        matrix.get9(tmp);
        writer->write(tmp, 9 * sizeof(SkScalar));
    } else if (tm & SkMatrix::kAffine_Mask) {
        tmp[0] = matrix[SkMatrix::kMScaleX];
        tmp[1] = matrix[SkMatrix::kMSkewX];
        tmp[2] = matrix[SkMatrix::kMTransX];
        tmp[3] = matrix[SkMatrix::kMScaleY];
        tmp[4] = matrix[SkMatrix::kMSkewY];
        tmp[5] = matrix[SkMatrix::kMTransY];
        writer->write(tmp, 6 * sizeof(SkScalar));
    } else if (tm & SkMatrix::kScale_Mask) {
        tmp[0] = matrix[SkMatrix::kMScaleX];
        tmp[1] = matrix[SkMatrix::kMTransX];
        tmp[2] = matrix[SkMatrix::kMScaleY];
        tmp[3] = matrix[SkMatrix::kMTransY];
        writer->write(tmp, 4 * sizeof(SkScalar));
    } else if (tm & SkMatrix::kTranslate_Mask) {
        tmp[0] = matrix[SkMatrix::kMTransX];
        tmp[1] = matrix[SkMatrix::kMTransY];
        writer->write(tmp, 2 * sizeof(SkScalar));
    }
    // else write nothing for Identity
}
예제 #9
0
static inline bool CanApplyDstMatrixAsCTM(const SkMatrix& m, const SkPaint& paint) {
    if (!paint.getMaskFilter()) {
        return true;
    }

    // Some mask filters parameters (sigma) depend on the CTM/scale.
    return m.getType() <= SkMatrix::kTranslate_Mask;
}
예제 #10
0
void SkPictureRecord::recordScale(const SkMatrix& m) {
    SkASSERT(SkMatrix::kScale_Mask == m.getType());

    // op + sx + sy
    size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
    size_t initialOffset = this->addDraw(SCALE, &size);
    this->addScalar(m.getScaleX());
    this->addScalar(m.getScaleY());
    this->validate(initialOffset, size);
}
예제 #11
0
void SkPictureRecord::recordTranslate(const SkMatrix& m) {
    SkASSERT(SkMatrix::kTranslate_Mask == m.getType());

    // op + dx + dy
    size_t size = 1 * kUInt32Size + 2 * sizeof(SkScalar);
    size_t initialOffset = this->addDraw(TRANSLATE, &size);
    this->addScalar(m.getTranslateX());
    this->addScalar(m.getTranslateY());
    this->validate(initialOffset, size);
}
예제 #12
0
SkShader::MatrixClass SkShader::ComputeMatrixClass(const SkMatrix& mat) {
    MatrixClass mc = kLinear_MatrixClass;

    if (mat.getType() & SkMatrix::kPerspective_Mask) {
        if (mat.fixedStepInX(0, NULL, NULL)) {
            mc = kFixedStepInX_MatrixClass;
        } else {
            mc = kPerspective_MatrixClass;
        }
    }
    return mc;
}
예제 #13
0
static void do_concat(SkWStream* stream, const SkMatrix& matrix, bool isSetMatrix) {
    unsigned mtype = matrix.getType();
    SkASSERT(0 == (mtype & ~kTypeMask_ConcatMask));
    unsigned extra = mtype;
    if (isSetMatrix) {
        extra |= kSetMatrix_ConcatMask;
    }
    if (mtype || isSetMatrix) {
        stream->write32(pack_verb(SkPipeVerb::kConcat, extra));
        write_sparse_matrix(stream, matrix);
    }
}
sk_sp<SkImageFilter> SkLocalMatrixImageFilter::Make(const SkMatrix& localM,
                                                    sk_sp<SkImageFilter> input) {
    if (!input) {
        return nullptr;
    }
    if (localM.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
        return nullptr;
    }
    if (localM.isIdentity()) {
        return input;
    }
    return sk_sp<SkImageFilter>(new SkLocalMatrixImageFilter(localM, input));
}
예제 #15
0
void SkPictureRecord::didConcat(const SkMatrix& matrix) {
    switch (matrix.getType()) {
        case SkMatrix::kTranslate_Mask:
            this->recordTranslate(matrix);
            break;
        case SkMatrix::kScale_Mask:
            this->recordScale(matrix);
            break;
        default:
            this->recordConcat(matrix);
            break;
    }
    this->INHERITED::didConcat(matrix);
}
예제 #16
0
static bool just_trans_general(const SkMatrix& matrix) {
    SkASSERT(matrix_only_scale_translate(matrix));

    if (matrix.getType() & SkMatrix::kScale_Mask) {
        const SkScalar tol = SK_Scalar1 / 32768;

        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
            return false;
        }
        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
            return false;
        }
    }
    // if we got here, treat us as either kTranslate_Mask or identity
    return true;
}
예제 #17
0
/**
 *  For the purposes of drawing bitmaps, if a matrix is "almost" translate
 *  go ahead and treat it as if it were, so that subsequent code can go fast.
 */
static bool just_trans_clamp(const SkMatrix& matrix, const SkBitmap& bitmap) {
    SkMatrix::TypeMask mask = matrix.getType();

    if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
        return false;
    }
    if (mask & SkMatrix::kScale_Mask) {
        SkScalar sx = matrix[SkMatrix::kMScaleX];
        SkScalar sy = matrix[SkMatrix::kMScaleY];
        int w = bitmap.width();
        int h = bitmap.height();
        int sw = SkScalarRound(SkScalarMul(sx, SkIntToScalar(w)));
        int sh = SkScalarRound(SkScalarMul(sy, SkIntToScalar(h)));
        return sw == w && sh == h;
    }
    // if we got here, we're either kTranslate_Mask or identity
    return true;
}
예제 #18
0
void SkGPipeCanvas::didConcat(const SkMatrix& matrix) {
    if (!matrix.isIdentity()) {
        NOTIFY_SETUP(this);
        switch (matrix.getType()) {
            case SkMatrix::kTranslate_Mask:
                this->recordTranslate(matrix);
                break;
            case SkMatrix::kScale_Mask:
                this->recordScale(matrix);
                break;
            default:
                this->recordConcat(matrix);
                break;
        }
    }

    this->INHERITED::didConcat(matrix);
}
예제 #19
0
void SkJSONCanvas::didConcat(const SkMatrix& matrix) {
    Json::Value command(Json::objectValue);
    switch (matrix.getType()) {
        case SkMatrix::kTranslate_Mask:
            command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_TRANSLATE);
            command[SKJSONCANVAS_ATTRIBUTE_X] = Json::Value(matrix.get(SkMatrix::kMTransX));
            command[SKJSONCANVAS_ATTRIBUTE_Y] = Json::Value(matrix.get(SkMatrix::kMTransY));
            break;
        case SkMatrix::kScale_Mask:
            command[SKJSONCANVAS_COMMAND] = Json::Value(SKJSONCANVAS_COMMAND_SCALE);
            command[SKJSONCANVAS_ATTRIBUTE_X] = Json::Value(matrix.get(SkMatrix::kMScaleX));
            command[SKJSONCANVAS_ATTRIBUTE_Y] = Json::Value(matrix.get(SkMatrix::kMScaleY));
            break;
        default:
            this->didSetMatrix(this->getTotalMatrix());
            return;
    }
    fCommands.append(command);
}
예제 #20
0
static bool just_trans_general(const SkMatrix& matrix) {
    SkMatrix::TypeMask mask = matrix.getType();

    if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
        return false;
    }
    if (mask & SkMatrix::kScale_Mask) {
        const SkScalar tol = SK_Scalar1 / 32768;

        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleX] - SK_Scalar1, tol)) {
            return false;
        }
        if (!SkScalarNearlyZero(matrix[SkMatrix::kMScaleY] - SK_Scalar1, tol)) {
            return false;
        }
    }
    // if we got here, treat us as either kTranslate_Mask or identity
    return true;
}
예제 #21
0
bool SkDeferredCanvas::push_concat(const SkMatrix& mat) {
    if (mat.getType() > (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
        return false;
    }
    // At the moment, we don't know which ops can scale and which can also flip, so
    // we reject negative scales for now
    if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
        return false;
    }

    int index = fRecs.count() - 1;
    SkMatrix m;
    if (index >= 0 && fRecs[index].isConcat(&m)) {
        m.preConcat(mat);
        fRecs[index].setConcat(m);
    } else {
        fRecs.append()->setConcat(mat);
    }
    return true;
}
예제 #22
0
void SkDumpCanvas::didConcat(const SkMatrix& matrix) {
    SkString str;

    switch (matrix.getType()) {
        case SkMatrix::kTranslate_Mask:
            this->dump(kMatrix_Verb, nullptr, "translate(%g %g)",
                       SkScalarToFloat(matrix.getTranslateX()),
                       SkScalarToFloat(matrix.getTranslateY()));
            break;
        case SkMatrix::kScale_Mask:
            this->dump(kMatrix_Verb, nullptr, "scale(%g %g)",
                       SkScalarToFloat(matrix.getScaleX()),
                       SkScalarToFloat(matrix.getScaleY()));
            break;
        default:
            matrix.toString(&str);
            this->dump(kMatrix_Verb, nullptr, "concat(%s)", str.c_str());
            break;
    }

    this->INHERITED::didConcat(matrix);
}
예제 #23
0
bool SkBitmapProcState::chooseProcs(const SkMatrix& inv, const SkPaint& paint) {
    if (fOrigBitmap.width() == 0 || fOrigBitmap.height() == 0) {
        return false;
    }

    const SkMatrix* m;
    bool trivial_matrix = (inv.getType() & ~SkMatrix::kTranslate_Mask) == 0;
    bool clamp_clamp = SkShader::kClamp_TileMode == fTileModeX &&
    SkShader::kClamp_TileMode == fTileModeY;

    if (clamp_clamp || trivial_matrix) {
        m = &inv;
    } else {
        fUnitInvMatrix = inv;
        fUnitInvMatrix.postIDiv(fOrigBitmap.width(), fOrigBitmap.height());
        m = &fUnitInvMatrix;
    }

    fBitmap = &fOrigBitmap;
    if (fOrigBitmap.hasMipMap()) {
        int shift = fOrigBitmap.extractMipLevel(&fMipBitmap,
                                                SkScalarToFixed(m->getScaleX()),
                                                SkScalarToFixed(m->getSkewY()));

        if (shift > 0) {
            if (m != &fUnitInvMatrix) {
                fUnitInvMatrix = *m;
                m = &fUnitInvMatrix;
            }

            SkScalar scale = SkFixedToScalar(SK_Fixed1 >> shift);
            fUnitInvMatrix.postScale(scale, scale);

            // now point here instead of fOrigBitmap
            fBitmap = &fMipBitmap;
        }
    }
예제 #24
0
void LoggingCanvas::didConcat(const SkMatrix& matrix)
{
    AutoLogger logger(this);
    RefPtr<JSONObject> params;

    switch (matrix.getType()) {
    case SkMatrix::kTranslate_Mask:
        params = logger.logItemWithParams("translate");
        params->setNumber("dx", matrix.getTranslateX());
        params->setNumber("dy", matrix.getTranslateY());
        break;

    case SkMatrix::kScale_Mask:
        params = logger.logItemWithParams("scale");
        params->setNumber("scaleX", matrix.getScaleX());
        params->setNumber("scaleY", matrix.getScaleY());
        break;

    default:
        params = logger.logItemWithParams("concat");
        params->setArray("matrix", arrayForSkMatrix(matrix));
    }
    this->SkCanvas::didConcat(matrix);
}
예제 #25
0
static ResamplingMode computeResamplingMode(const SkMatrix& matrix, const NativeImageSkia& bitmap, float srcWidth, float srcHeight, float destWidth, float destHeight)
{
    // The percent change below which we will not resample. This usually means
    // an off-by-one error on the web page, and just doing nearest neighbor
    // sampling is usually good enough.
    const float kFractionalChangeThreshold = 0.025f;

    // Images smaller than this in either direction are considered "small" and
    // are not resampled ever (see below).
    const int kSmallImageSizeThreshold = 8;

    // The amount an image can be stretched in a single direction before we
    // say that it is being stretched so much that it must be a line or
    // background that doesn't need resampling.
    const float kLargeStretch = 3.0f;

    // Figure out if we should resample this image. We try to prune out some
    // common cases where resampling won't give us anything, since it is much
    // slower than drawing stretched.
    float diffWidth = fabs(destWidth - srcWidth);
    float diffHeight = fabs(destHeight - srcHeight);
    bool widthNearlyEqual = diffWidth < std::numeric_limits<float>::epsilon();
    bool heightNearlyEqual = diffHeight < std::numeric_limits<float>::epsilon();
    // We don't need to resample if the source and destination are the same.
    if (widthNearlyEqual && heightNearlyEqual)
        return RESAMPLE_NONE;

    if (srcWidth <= kSmallImageSizeThreshold
        || srcHeight <= kSmallImageSizeThreshold
        || destWidth <= kSmallImageSizeThreshold
        || destHeight <= kSmallImageSizeThreshold) {
        // Never resample small images. These are often used for borders and
        // rules (think 1x1 images used to make lines).
        return RESAMPLE_NONE;
    }

    if (srcHeight * kLargeStretch <= destHeight || srcWidth * kLargeStretch <= destWidth) {
        // Large image detected.

        // Don't resample if it is being stretched a lot in only one direction.
        // This is trying to catch cases where somebody has created a border
        // (which might be large) and then is stretching it to fill some part
        // of the page.
        if (widthNearlyEqual || heightNearlyEqual)
            return RESAMPLE_NONE;

        // The image is growing a lot and in more than one direction. Resampling
        // is slow and doesn't give us very much when growing a lot.
        return RESAMPLE_LINEAR;
    }

    if ((diffWidth / srcWidth < kFractionalChangeThreshold)
        && (diffHeight / srcHeight < kFractionalChangeThreshold)) {
        // It is disappointingly common on the web for image sizes to be off by
        // one or two pixels. We don't bother resampling if the size difference
        // is a small fraction of the original size.
        return RESAMPLE_NONE;
    }

    // When the image is not yet done loading, use linear. We don't cache the
    // partially resampled images, and as they come in incrementally, it causes
    // us to have to resample the whole thing every time.
    if (!bitmap.isDataComplete())
        return RESAMPLE_LINEAR;

    // Everything else gets resampled.
    // High quality interpolation only enabled for scaling and translation.
    if (!(matrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)))
        return RESAMPLE_AWESOME;
    
    return RESAMPLE_LINEAR;
}
void NativeImageSkia::draw(GraphicsContext* context, const SkRect& srcRect, const SkRect& destRect, PassRefPtr<SkXfermode> compOp) const
{
    TRACE_EVENT0("skia", "NativeImageSkia::draw");
    SkPaint paint;
    paint.setXfermode(compOp.get());
    paint.setColorFilter(context->colorFilter());
    paint.setAlpha(context->getNormalizedAlpha());
    paint.setLooper(context->drawLooper());
    // only antialias if we're rotated or skewed
    paint.setAntiAlias(hasNon90rotation(context));

    ResamplingMode resampling;
    if (context->isAccelerated()) {
        resampling = LinearResampling;
    } else if (context->printing()) {
        resampling = NoResampling;
    } else {
        // Take into account scale applied to the canvas when computing sampling mode (e.g. CSS scale or page scale).
        SkRect destRectTarget = destRect;
        SkMatrix totalMatrix = context->getTotalMatrix();
        if (!(totalMatrix.getType() & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)))
            totalMatrix.mapRect(&destRectTarget, destRect);

        resampling = computeResamplingMode(totalMatrix,
            SkScalarToFloat(srcRect.width()), SkScalarToFloat(srcRect.height()),
            SkScalarToFloat(destRectTarget.width()), SkScalarToFloat(destRectTarget.height()));
    }

    if (resampling == NoResampling) {
        // FIXME: This is to not break tests (it results in the filter bitmap flag
        // being set to true). We need to decide if we respect NoResampling
        // being returned from computeResamplingMode.
        resampling = LinearResampling;
    }
    resampling = limitResamplingMode(context, resampling);
    paint.setFilterBitmap(resampling == LinearResampling);

    bool isLazyDecoded = DeferredImageDecoder::isLazyDecoded(bitmap());
    // FIXME: Bicubic filtering in Skia is only applied to defer-decoded images
    // as an experiment. Once this filtering code path becomes stable we should
    // turn this on for all cases, including non-defer-decoded images.
    bool useBicubicFilter = resampling == AwesomeResampling && isLazyDecoded;

    if (useBicubicFilter)
        paint.setFilterLevel(SkPaint::kHigh_FilterLevel);

    if (resampling == AwesomeResampling && !useBicubicFilter) {
        // Resample the image and then draw the result to canvas with bilinear
        // filtering.
        drawResampledBitmap(context, paint, srcRect, destRect);
    } else {
        // We want to filter it if we decided to do interpolation above, or if
        // there is something interesting going on with the matrix (like a rotation).
        // Note: for serialization, we will want to subset the bitmap first so we
        // don't send extra pixels.
        context->drawBitmapRect(bitmap(), &srcRect, destRect, &paint);
    }
    if (isLazyDecoded)
        PlatformInstrumentation::didDrawLazyPixelRef(bitmap().getGenerationID());
    context->didDrawRect(destRect, paint, &bitmap());
}
예제 #27
0
void GrGLGeometryProcessor::emitTransforms(GrGLGPBuilder* pb,
                                           const GrShaderVar& posVar,
                                           const char* localCoords,
                                           const SkMatrix& localMatrix,
                                           const TransformsIn& tin,
                                           TransformsOut* tout) {
    GrGLVertexBuilder* vb = pb->getVertexShaderBuilder();
    tout->push_back_n(tin.count());
    fInstalledTransforms.push_back_n(tin.count());
    for (int i = 0; i < tin.count(); i++) {
        const ProcCoords& coordTransforms = tin[i];
        fInstalledTransforms[i].push_back_n(coordTransforms.count());
        for (int t = 0; t < coordTransforms.count(); t++) {
            SkString strUniName("StageMatrix");
            strUniName.appendf("_%i_%i", i, t);
            GrSLType varyingType;

            GrCoordSet coordType = coordTransforms[t]->sourceCoords();
            uint32_t type = coordTransforms[t]->getMatrix().getType();
            if (kLocal_GrCoordSet == coordType) {
                type |= localMatrix.getType();
            }
            varyingType = SkToBool(SkMatrix::kPerspective_Mask & type) ? kVec3f_GrSLType :
                                                                         kVec2f_GrSLType;
            GrSLPrecision precision = coordTransforms[t]->precision();

            const char* uniName;
            fInstalledTransforms[i][t].fHandle =
                    pb->addUniform(GrGLProgramBuilder::kVertex_Visibility,
                                   kMat33f_GrSLType, precision,
                                   strUniName.c_str(),
                                   &uniName).toShaderBuilderIndex();

            SkString strVaryingName("MatrixCoord");
            strVaryingName.appendf("_%i_%i", i, t);

            GrGLVertToFrag v(varyingType);
            pb->addVarying(strVaryingName.c_str(), &v, precision);

            SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
            SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLProcessor::TransformedCoords,
                                   (SkString(v.fsIn()), varyingType));

            // varying = matrix * coords (logically)
            if (kDevice_GrCoordSet == coordType) {
                if (kVec2f_GrSLType == varyingType) {
                    if (kVec2f_GrSLType == posVar.getType()) {
                        vb->codeAppendf("%s = (%s * vec3(%s, 1)).xy;",
                                        v.vsOut(), uniName, posVar.c_str());
                    } else {
                        // The brackets here are just to scope the temp variable
                        vb->codeAppendf("{ vec3 temp = %s * %s;", uniName, posVar.c_str());
                        vb->codeAppendf("%s = vec2(temp.x/temp.z, temp.y/temp.z); }", v.vsOut());
                    }
                } else {
                    if (kVec2f_GrSLType == posVar.getType()) {
                        vb->codeAppendf("%s = %s * vec3(%s, 1);",
                                        v.vsOut(), uniName, posVar.c_str());
                    } else {
                        vb->codeAppendf("%s = %s * %s;", v.vsOut(), uniName, posVar.c_str());
                    }
                }
            } else {
                if (kVec2f_GrSLType == varyingType) {
                    vb->codeAppendf("%s = (%s * vec3(%s, 1)).xy;", v.vsOut(), uniName, localCoords);
                } else {
                    vb->codeAppendf("%s = %s * vec3(%s, 1);", v.vsOut(), uniName, localCoords);
                }
            }
        }
    }
}
예제 #28
0
// true iff the matrix has a scale and no more than an optional translate.
static bool matrix_only_scale_translate(const SkMatrix& m) {
    return (m.getType() & ~SkMatrix::kTranslate_Mask) == SkMatrix::kScale_Mask;
}
예제 #29
0
static bool only_scale_and_translate(const SkMatrix& matrix) {
    unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
    return (matrix.getType() & ~mask) == 0;
}
예제 #30
0
// true iff the matrix contains, at most, scale and translate elements
static bool matrix_only_scale_translate(const SkMatrix& m) {
    return m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask);
}