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; }
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()); }
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()); } }
/** * 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; }
/** * 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); }
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; } }
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; }
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 }
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; }
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); }
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); }
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; }
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)); }
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); }
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; }
/** * 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; }
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); }
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); }
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; }
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; }
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); }
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; } }
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); }
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()); }
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); } } } } }
// 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; }
static bool only_scale_and_translate(const SkMatrix& matrix) { unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; return (matrix.getType() & ~mask) == 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); }