void GrDrawContext::drawPaint(GrRenderTarget* rt, const GrClip& clip, const GrPaint& origPaint, const SkMatrix& viewMatrix) { RETURN_IF_ABANDONED // set rect to be big enough to fill the space, but not super-huge, so we // don't overflow fixed-point implementations SkRect r; r.setLTRB(0, 0, SkIntToScalar(rt->width()), SkIntToScalar(rt->height())); SkTCopyOnFirstWrite<GrPaint> paint(origPaint); // by definition this fills the entire clip, no need for AA if (paint->isAntiAlias()) { paint.writable()->setAntiAlias(false); } bool isPerspective = viewMatrix.hasPerspective(); // We attempt to map r by the inverse matrix and draw that. mapRect will // map the four corners and bound them with a new rect. This will not // produce a correct result for some perspective matrices. if (!isPerspective) { SkMatrix inverse; if (!viewMatrix.invert(&inverse)) { SkDebugf("Could not invert matrix\n"); return; } inverse.mapRect(&r); this->drawRect(rt, clip, *paint, viewMatrix, r); } else { SkMatrix localMatrix; if (!viewMatrix.invert(&localMatrix)) { SkDebugf("Could not invert matrix\n"); return; } AutoCheckFlush acf(fContext); if (!this->prepareToDraw(rt)) { return; } GrPipelineBuilder pipelineBuilder(*paint, rt, clip); fDrawTarget->drawBWRect(pipelineBuilder, paint->getColor(), SkMatrix::I(), r, NULL, &localMatrix); } }
bool Surface::paint(SkCanvas* canvas) { if (singleLayer()) { getFirstLayer()->contentDraw(canvas, Layer::UnmergedLayers); // TODO: double buffer by disabling SurfaceCollection swaps and position // updates until painting complete // In single surface mode, draw layer content onto the base layer if (isBase() && getFirstLayer()->countChildren() && getFirstLayer()->state()->isSingleSurfaceRenderingMode()) { for (int i = 0; i < getFirstLayer()->countChildren(); i++) getFirstLayer()->getChild(i)->drawCanvas(canvas, true, Layer::FlattenedLayers); } } else { SkAutoCanvasRestore acr(canvas, true); SkMatrix matrix; GLUtils::toSkMatrix(matrix, m_drawTransform); SkMatrix inverse; inverse.reset(); matrix.invert(&inverse); SkMatrix canvasMatrix = canvas->getTotalMatrix(); inverse.postConcat(canvasMatrix); canvas->setMatrix(inverse); for (unsigned int i=0; i<m_layers.size(); i++) m_layers[i]->drawCanvas(canvas, false, Layer::MergedLayers); } return true; }
void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture, GrDrawTarget* target, GrPipelineBuilder* pipelineBuilder, GrColor color, const SkMatrix& viewMatrix, const SkIRect& rect) { SkMatrix invert; if (!viewMatrix.invert(&invert)) { return; } GrPipelineBuilder::AutoRestoreFragmentProcessors arfp(pipelineBuilder); SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft, SK_Scalar1 * rect.fTop, SK_Scalar1 * rect.fRight, SK_Scalar1 * rect.fBottom); // We use device coords to compute the texture coordinates. We take the device coords and apply // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling // matrix to normalized coords. SkMatrix maskMatrix; maskMatrix.setIDiv(texture->width(), texture->height()); maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop)); pipelineBuilder->addCoverageProcessor( GrSimpleTextureEffect::Create(texture, maskMatrix, GrTextureParams::kNone_FilterMode, kDevice_GrCoordSet))->unref(); target->drawRect(pipelineBuilder, color, SkMatrix::I(), dstRect, NULL, &invert); }
SkPoint invertPt(SkScalar x, SkScalar y) { SkPoint pt; SkMatrix m; fMatrix.invert(&m); m.mapXY(x, y, &pt); return pt; }
void GrSWMaskHelper::DrawToTargetWithShapeMask(sk_sp<GrTextureProxy> proxy, GrRenderTargetContext* renderTargetContext, GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, const GrClip& clip, const SkMatrix& viewMatrix, const SkIPoint& textureOriginInDeviceSpace, const SkIRect& deviceSpaceRectToDraw) { SkMatrix invert; if (!viewMatrix.invert(&invert)) { return; } GrResourceProvider* resourceProvider = renderTargetContext->resourceProvider(); SkRect dstRect = SkRect::Make(deviceSpaceRectToDraw); // We use device coords to compute the texture coordinates. We take the device coords and apply // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling // matrix to normalized coords. SkMatrix maskMatrix = SkMatrix::MakeTrans(SkIntToScalar(-textureOriginInDeviceSpace.fX), SkIntToScalar(-textureOriginInDeviceSpace.fY)); maskMatrix.preConcat(viewMatrix); std::unique_ptr<GrLegacyMeshDrawOp> op = GrRectOpFactory::MakeNonAAFill( paint.getColor(), SkMatrix::I(), dstRect, nullptr, &invert); paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make( resourceProvider, std::move(proxy), nullptr, maskMatrix, GrSamplerParams::kNone_FilterMode)); GrPipelineBuilder pipelineBuilder(std::move(paint), GrAAType::kNone); pipelineBuilder.setUserStencil(&userStencilSettings); renderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), clip, std::move(op)); }
static bool inverse_transform_bbox(const SkMatrix& matrix, SkRect* bbox) { SkMatrix inverse; if (!matrix.invert(&inverse)) { return false; } inverse.mapRect(bbox); return true; }
Boolean Matrix::NativeInvert( /* [in] */ Int64 matrixHandle, /* [in] */ Int64 inverseHandle) { SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); SkMatrix* inverse = reinterpret_cast<SkMatrix*>(inverseHandle); return matrix->invert(inverse); }
virtual void onDraw(SkCanvas* canvas) { SkMatrix m; m.reset(); m.setRotate(33 * SK_Scalar1); m.postScale(3000 * SK_Scalar1, 3000 * SK_Scalar1); m.postTranslate(6000 * SK_Scalar1, -5000 * SK_Scalar1); canvas->concat(m); SkPaint paint; paint.setColor(SK_ColorRED); paint.setAntiAlias(true); bool success = m.invert(&m); SkASSERT(success); (void) success; // silence compiler :( SkPath path; SkPoint pt = {10 * SK_Scalar1, 10 * SK_Scalar1}; SkScalar small = 1 / (500 * SK_Scalar1); m.mapPoints(&pt, 1); path.addCircle(pt.fX, pt.fY, small); canvas->drawPath(path, paint); pt.set(30 * SK_Scalar1, 10 * SK_Scalar1); m.mapPoints(&pt, 1); SkRect rect = {pt.fX - small, pt.fY - small, pt.fX + small, pt.fY + small}; canvas->drawRect(rect, paint); SkBitmap bmp; bmp.setConfig(SkBitmap::kARGB_8888_Config, 2, 2); bmp.allocPixels(); bmp.lockPixels(); uint32_t* pixels = reinterpret_cast<uint32_t*>(bmp.getPixels()); pixels[0] = SkPackARGB32(0xFF, 0xFF, 0x00, 0x00); pixels[1] = SkPackARGB32(0xFF, 0x00, 0xFF, 0x00); pixels[2] = SkPackARGB32(0x80, 0x00, 0x00, 0x00); pixels[3] = SkPackARGB32(0xFF, 0x00, 0x00, 0xFF); bmp.unlockPixels(); pt.set(30 * SK_Scalar1, 30 * SK_Scalar1); m.mapPoints(&pt, 1); SkShader* shader = SkShader::CreateBitmapShader( bmp, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix s; s.reset(); s.setScale(SK_Scalar1 / 1000, SK_Scalar1 / 1000); shader->setLocalMatrix(s); paint.setShader(shader)->unref(); paint.setAntiAlias(false); paint.setFilterLevel(SkPaint::kLow_FilterLevel); rect.setLTRB(pt.fX - small, pt.fY - small, pt.fX + small, pt.fY + small); canvas->drawRect(rect, paint); }
sk_sp<SkNormalSource> SkNormalSource::MakeFromNormalMap(sk_sp<SkShader> map, const SkMatrix& ctm) { SkMatrix invCTM; if (!ctm.invert(&invCTM) || !map) { return nullptr; } return sk_make_sp<SkNormalMapSourceImpl>(std::move(map), invCTM); }
bool SkNormalMapSourceImpl::computeNormTotalInverse(const SkShaderBase::ContextRec& rec, SkMatrix* normTotalInverse) const { SkMatrix total = SkMatrix::Concat(*rec.fMatrix, fMapShader->getLocalMatrix()); if (rec.fLocalMatrix) { total.preConcat(*rec.fLocalMatrix); } return total.invert(normTotalInverse); }
bool GrAAHairLinePathRenderer::createGeom( const SkPath& path, GrDrawTarget* target, int* lineCnt, int* quadCnt, GrDrawTarget::AutoReleaseGeometry* arg) { const GrDrawState& drawState = target->getDrawState(); int rtHeight = drawState.getRenderTarget()->height(); GrIRect devClipBounds; target->getClip()->getConservativeBounds(drawState.getRenderTarget(), &devClipBounds); GrVertexLayout layout = GrDrawState::kEdge_VertexLayoutBit; SkMatrix viewM = drawState.getViewMatrix(); PREALLOC_PTARRAY(128) lines; PREALLOC_PTARRAY(128) quads; IntArray qSubdivs; *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, &lines, &quads, &qSubdivs); *lineCnt = lines.count() / 2; int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt; GrAssert(sizeof(Vertex) == GrDrawState::VertexSize(layout)); if (!arg->set(target, layout, vertCnt, 0)) { return false; } Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); const SkMatrix* toDevice = NULL; const SkMatrix* toSrc = NULL; SkMatrix ivm; if (viewM.hasPerspective()) { if (viewM.invert(&ivm)) { toDevice = &viewM; toSrc = &ivm; } } for (int i = 0; i < *lineCnt; ++i) { add_line(&lines[2*i], rtHeight, toSrc, &verts); } int unsubdivQuadCnt = quads.count() / 3; for (int i = 0; i < unsubdivQuadCnt; ++i) { GrAssert(qSubdivs[i] >= 0); add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts); } return true; }
void draw(SkCanvas* canvas) { SkMatrix matrix; matrix.setAll(1, 0, 0, 0, 1, 0, 0, 0, 0); if (matrix.invert(&matrix)) { SkScalar factor[2] = {2, 2}; bool result = matrix.getMinMaxScales(factor); SkDebugf("matrix.getMinMaxScales() %s %g %g\n", result ? "true" : "false", factor[0], factor[1]); } }
static void android_view_RenderNode_getInverseTransformMatrix(JNIEnv* env, jobject clazz, jlong renderNodePtr, jlong outMatrixPtr) { // load transform matrix android_view_RenderNode_getTransformMatrix(env, clazz, renderNodePtr, outMatrixPtr); SkMatrix* outMatrix = reinterpret_cast<SkMatrix*>(outMatrixPtr); // return it inverted if (!outMatrix->invert(outMatrix)) { // failed to load inverse, pass back identity outMatrix->setIdentity(); } }
SkGLDevice::TexCache* SkGLDevice::setupGLPaintShader(const SkPaint& paint) { SkGL::SetPaint(paint); SkShader* shader = paint.getShader(); if (NULL == shader) { return NULL; } if (!shader->setContext(this->accessBitmap(false), paint, this->matrix())) { return NULL; } SkBitmap bitmap; SkMatrix matrix; SkShader::TileMode tileModes[2]; if (!shader->asABitmap(&bitmap, &matrix, tileModes)) { return NULL; } bitmap.lockPixels(); if (!bitmap.readyToDraw()) { return NULL; } // see if we've already cached the bitmap from the shader SkPoint max; GLuint name; TexCache* cache = SkGLDevice::LockTexCache(bitmap, &name, &max); // the lock has already called glBindTexture for us SkGL::SetTexParams(paint.isFilterBitmap(), tileModes[0], tileModes[1]); // since our texture coords will be in local space, we wack the texture // matrix to map them back into 0...1 before we load it SkMatrix localM; if (shader->getLocalMatrix(&localM)) { SkMatrix inverse; if (localM.invert(&inverse)) { matrix.preConcat(inverse); } } matrix.postScale(max.fX / bitmap.width(), max.fY / bitmap.height()); glMatrixMode(GL_TEXTURE); SkGL::LoadMatrix(matrix); glMatrixMode(GL_MODELVIEW); // since we're going to use a shader/texture, we don't want the color, // just its alpha SkGL::SetAlpha(paint.getAlpha()); // report that we have setup the texture return cache; }
bool SkView::globalToLocal(SkScalar x, SkScalar y, SkPoint* local) const { if (local) { SkMatrix m; this->localToGlobal(&m); if (!m.invert(&m)) { return false; } SkPoint p; m.mapXY(x, y, &p); local->set(p.fX, p.fY); } return true; }
// Solves linear system to extract klm // P.K = k (similarly for l, m) // Where P is matrix of control points // K is coefficients for the line K // k is vector of values of K evaluated at the control points // Solving for K, thus K = P^(-1) . k static void calc_cubic_klm(const SkPoint p[4], const SkScalar controlK[4], const SkScalar controlL[4], const SkScalar controlM[4], SkScalar k[3], SkScalar l[3], SkScalar m[3]) { SkMatrix matrix; matrix.setAll(p[0].fX, p[0].fY, 1.f, p[1].fX, p[1].fY, 1.f, p[2].fX, p[2].fY, 1.f); SkMatrix inverse; if (matrix.invert(&inverse)) { inverse.mapHomogeneousPoints(k, controlK, 1); inverse.mapHomogeneousPoints(l, controlL, 1); inverse.mapHomogeneousPoints(m, controlM, 1); } }
FloatRect FEBoxReflect::mapRect(const FloatRect& rect, bool forward) { SkMatrix flipMatrix = SkiaImageFilterBuilder().matrixForBoxReflectFilter( m_reflectionDirection, m_offset); if (!forward) { bool inverted = flipMatrix.invert(&flipMatrix); DCHECK(inverted) << "box reflect matrix must be invertible"; } SkRect reflection(rect); flipMatrix.mapRect(&reflection); FloatRect result = rect; result.unite(reflection); return result; }
/* [0] 9.9999997e-005 float [1] 9.0000003e-006 float [2] 7.0000001e-006 float [3] 1000000.0 float [4] 90639.000 float [5] 70000.000 float [6] 0.00000000 float [7] 0.00000000 float [8] 1.0000000 float */ static void testinvert2() { const float val[] = { 9.9999997e-005, 9.0000003e-006, 7.0000001e-006, 1000000.0, 90639.000, 70000.000 }; SkMatrix matrix; setmatrix6(&matrix, val); matrix.dump(); SkMatrix inverse; matrix.invert(&inverse); inverse.dump(); matrix.preConcat(inverse); matrix.dump(); // result is that matrix[3] is 49550 instead of 0 :( }
// Draw a mask using the supplied paint. Since the coverage/geometry // is already burnt into the mask this boils down to a rect draw. // Return true if the mask was successfully drawn. static bool draw_mask(GrDrawContext* drawContext, const GrClip& clip, const SkMatrix& viewMatrix, const SkRect& maskRect, GrPaint* grp, GrTexture* mask) { SkMatrix matrix; matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop); matrix.postIDiv(mask->width(), mask->height()); grp->addCoverageFragmentProcessor(GrSimpleTextureEffect::Create(mask, matrix, kDevice_GrCoordSet))->unref(); SkMatrix inverse; if (!viewMatrix.invert(&inverse)) { return false; } drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), maskRect, inverse); return true; }
sk_sp<GrGeometryProcessor> GrDefaultGeoProcFactory::MakeForDeviceSpace( const Color& color, const Coverage& coverage, const LocalCoords& localCoords, const SkMatrix& viewMatrix) { SkMatrix invert = SkMatrix::I(); if (LocalCoords::kUnused_Type != localCoords.fType) { SkASSERT(LocalCoords::kUsePosition_Type == localCoords.fType); if (!viewMatrix.isIdentity() && !viewMatrix.invert(&invert)) { return nullptr; } if (localCoords.hasLocalMatrix()) { invert.preConcat(*localCoords.fMatrix); } } LocalCoords inverted(LocalCoords::kUsePosition_Type, &invert); return Make(color, coverage, inverted, SkMatrix::I()); }
// Draw a mask using the supplied paint. Since the coverage/geometry // is already burnt into the mask this boils down to a rect draw. // Return true if the mask was successfully drawn. static bool draw_mask(GrDrawContext* drawContext, const GrClip& clip, const SkMatrix& viewMatrix, const SkIRect& maskRect, GrPaint* grp, GrTexture* mask) { SkMatrix matrix; matrix.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); matrix.postIDiv(mask->width(), mask->height()); matrix.preConcat(viewMatrix); grp->addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(mask, nullptr, matrix)); SkMatrix inverse; if (!viewMatrix.invert(&inverse)) { return false; } drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), SkRect::Make(maskRect), inverse); return true; }
WarpView() { SkBitmap bm; // SkImageDecoder::DecodeFile("/skimages/marker.png", &bm); SkImageDecoder::DecodeFile("/skimages/logo.gif", &bm); // SkImageDecoder::DecodeFile("/beach_shot.JPG", &bm); fBitmap = bm; SkRect bounds, texture; texture.set(0, 0, SkIntToScalar(fBitmap.width()), SkIntToScalar(fBitmap.height())); bounds = texture; // fMesh.init(bounds, fBitmap.width() / 40, fBitmap.height() / 40, texture); fMesh.init(bounds, fBitmap.width()/16, fBitmap.height()/16, texture); fOrig = fMesh; fP0.set(0, 0); fP1 = fP0; fMatrix.setScale(2, 2); fMatrix.invert(&fInverse); }
void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture, GrDrawContext* drawContext, const GrPaint* paint, const GrUserStencilSettings* userStencilSettings, const GrClip& clip, GrColor color, const SkMatrix& viewMatrix, const SkIRect& rect) { SkMatrix invert; if (!viewMatrix.invert(&invert)) { return; } SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft, SK_Scalar1 * rect.fTop, SK_Scalar1 * rect.fRight, SK_Scalar1 * rect.fBottom); // We use device coords to compute the texture coordinates. We take the device coords and apply // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling // matrix to normalized coords. SkMatrix maskMatrix; maskMatrix.setIDiv(texture->width(), texture->height()); maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop)); GrPipelineBuilder pipelineBuilder(*paint, drawContext->isUnifiedMultisampled()); pipelineBuilder.setRenderTarget(drawContext->accessRenderTarget()); pipelineBuilder.setUserStencil(userStencilSettings); pipelineBuilder.addCoverageFragmentProcessor( GrSimpleTextureEffect::Create(texture, maskMatrix, GrTextureParams::kNone_FilterMode, kDevice_GrCoordSet))->unref(); SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateNonAAFill(color, SkMatrix::I(), dstRect, nullptr, &invert)); drawContext->drawBatch(pipelineBuilder, clip, batch); }
void GrSoftwarePathRenderer::DrawAroundInvPath(GrDrawContext* drawContext, const GrPaint* paint, const GrUserStencilSettings* userStencilSettings, const GrClip& clip, GrColor color, const SkMatrix& viewMatrix, const SkIRect& devClipBounds, const SkIRect& devPathBounds) { SkMatrix invert; if (!viewMatrix.invert(&invert)) { return; } SkRect rect; if (devClipBounds.fTop < devPathBounds.fTop) { rect.iset(devClipBounds.fLeft, devClipBounds.fTop, devClipBounds.fRight, devPathBounds.fTop); DrawNonAARect(drawContext, paint, userStencilSettings, clip, color, SkMatrix::I(), rect, invert); } if (devClipBounds.fLeft < devPathBounds.fLeft) { rect.iset(devClipBounds.fLeft, devPathBounds.fTop, devPathBounds.fLeft, devPathBounds.fBottom); DrawNonAARect(drawContext, paint, userStencilSettings, clip, color, SkMatrix::I(), rect, invert); } if (devClipBounds.fRight > devPathBounds.fRight) { rect.iset(devPathBounds.fRight, devPathBounds.fTop, devClipBounds.fRight, devPathBounds.fBottom); DrawNonAARect(drawContext, paint, userStencilSettings, clip, color, SkMatrix::I(), rect, invert); } if (devClipBounds.fBottom > devPathBounds.fBottom) { rect.iset(devClipBounds.fLeft, devPathBounds.fBottom, devClipBounds.fRight, devClipBounds.fBottom); DrawNonAARect(drawContext, paint, userStencilSettings, clip, color, SkMatrix::I(), rect, invert); } }
bool SkMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMatrix& ctm, SkIRect* dst) const { SkMatrix transformInverse; if (!fTransform.invert(&transformInverse)) { return false; } SkMatrix matrix; if (!ctm.invert(&matrix)) { return false; } matrix.postConcat(transformInverse); matrix.postConcat(ctm); SkRect floatBounds; matrix.mapRect(&floatBounds, SkRect::Make(src)); SkIRect bounds = floatBounds.roundOut(); if (getInput(0) && !getInput(0)->filterBounds(bounds, ctm, &bounds)) { return false; } *dst = bounds; return true; }
// This test case including path coords and matrix taken from crbug.com/627443. // Because of inaccuracies in large floating point values this causes the // the path renderer to attempt to add a path DF to its atlas that is larger // than the plot size which used to crash rather than fail gracefully. static void test_far_from_origin(GrDrawContext* drawContext, GrPathRenderer* pr, GrResourceProvider* rp) { SkPath path; path.lineTo(49.0255089839f, 0.473541f); static constexpr SkScalar mvals[] = {14.0348252854f, 2.13026182736f, 13.6122547187f, 118.309922702f, 1912337682.09f, 2105391889.87f}; SkMatrix matrix; matrix.setAffine(mvals); SkMatrix inverse; SkAssertResult(matrix.invert(&inverse)); path.transform(inverse); SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); rec.setStrokeStyle(1.f); rec.setStrokeParams(SkPaint::kRound_Cap, SkPaint::kRound_Join, 1.f); GrStyle style(rec, nullptr); GrShape shape(path, style); shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, 1.f); GrPaint paint; paint.setXPFactory(GrPorterDuffXPFactory::Make(SkXfermode::kSrc_Mode)); GrNoClip noClip; GrPathRenderer::DrawPathArgs args; args.fPaint = &paint; args.fUserStencilSettings = &GrUserStencilSettings::kUnused; args.fDrawContext = drawContext; args.fClip = &noClip; args.fResourceProvider = rp; args.fViewMatrix = &matrix; args.fShape = &shape; args.fAntiAlias = true; args.fGammaCorrect = false; args.fColor = 0x0; pr->drawPath(args); }
static void testinvert() { SkMatrix matrix; const float vals[] = { 0,9,.000001,10000,0,0 }; setmatrix6(&matrix, vals); const float vals2[] = { 0,100,71,9,0,7 }; SkMatrix tmp; setmatrix6(&tmp, vals2); matrix.preConcat(tmp); matrix.dump(); SkMatrix inverse; matrix.invert(&inverse); inverse.dump(); matrix.preConcat(inverse); matrix.dump(); // o2dContext.setTransform(0,9,.000001,10000,0,0); // o2dContext.transform(0,100,71,9,0,7); // o2dContext.setTransform(0,6,95,4,1,0); }
// Attempt to trim the line to minimally cover the cull rect (currently // only works for horizontal and vertical lines). // Return true if processing should continue; false otherwise. static bool cull_line(SkPoint* pts, const SkStrokeRec& rec, const SkMatrix& ctm, const SkRect* cullRect, const SkScalar intervalLength) { if (nullptr == cullRect) { SkASSERT(false); // Shouldn't ever occur in practice return false; } SkScalar dx = pts[1].x() - pts[0].x(); SkScalar dy = pts[1].y() - pts[0].y(); if ((dx && dy) || (!dx && !dy)) { return false; } SkRect bounds = *cullRect; outset_for_stroke(&bounds, rec); // cullRect is in device space while pts are in the local coordinate system // defined by the ctm. We want our answer in the local coordinate system. SkASSERT(ctm.rectStaysRect()); SkMatrix inv; if (!ctm.invert(&inv)) { return false; } inv.mapRect(&bounds); if (dx) { SkASSERT(dx && !dy); SkScalar minX = pts[0].fX; SkScalar maxX = pts[1].fX; if (dx < 0) { SkTSwap(minX, maxX); } SkASSERT(minX < maxX); if (maxX <= bounds.fLeft || minX >= bounds.fRight) { return false; } // Now we actually perform the chop, removing the excess to the left and // right of the bounds (keeping our new line "in phase" with the dash, // hence the (mod intervalLength). if (minX < bounds.fLeft) { minX = bounds.fLeft - SkScalarMod(bounds.fLeft - minX, intervalLength); } if (maxX > bounds.fRight) { maxX = bounds.fRight + SkScalarMod(maxX - bounds.fRight, intervalLength); } SkASSERT(maxX > minX); if (dx < 0) { SkTSwap(minX, maxX); } pts[0].fX = minX; pts[1].fX = maxX; } else { SkASSERT(dy && !dx); SkScalar minY = pts[0].fY; SkScalar maxY = pts[1].fY; if (dy < 0) { SkTSwap(minY, maxY); } SkASSERT(minY < maxY); if (maxY <= bounds.fTop || minY >= bounds.fBottom) { return false; } // Now we actually perform the chop, removing the excess to the top and // bottom of the bounds (keeping our new line "in phase" with the dash, // hence the (mod intervalLength). if (minY < bounds.fTop) { minY = bounds.fTop - SkScalarMod(bounds.fTop - minY, intervalLength); } if (maxY > bounds.fBottom) { maxY = bounds.fBottom + SkScalarMod(maxY - bounds.fBottom, intervalLength); } SkASSERT(maxY > minY); if (dy < 0) { SkTSwap(minY, maxY); } pts[0].fY = minY; pts[1].fY = maxY; } return true; }
void GrBitmapTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, SkScalar x, SkScalar y) { SkASSERT(byteLength == 0 || text != NULL); // nothing to draw if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { return; } this->init(rt, clip, paint, skPaint); SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix); SkGlyphCache* cache = autoCache.getCache(); GrFontScaler* fontScaler = GetGrFontScaler(cache); // transform our starting point { SkPoint loc; viewMatrix.mapXY(x, y, &loc); x = loc.fX; y = loc.fY; } // need to measure first int numGlyphs; if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { SkVector stopVector; numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector); SkScalar stopX = stopVector.fX; SkScalar stopY = stopVector.fY; if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { stopX = SkScalarHalf(stopX); stopY = SkScalarHalf(stopY); } x -= stopX; y -= stopY; } else { numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); } fTotalVertexCount = kVerticesPerGlyph*numGlyphs; const char* stop = text + byteLength; SkAutoKern autokern; SkFixed fxMask = ~0; SkFixed fyMask = ~0; SkScalar halfSampleX, halfSampleY; if (cache->isSubpixel()) { halfSampleX = halfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound); SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix); if (kX_SkAxisAlignment == baseline) { fyMask = 0; halfSampleY = SK_ScalarHalf; } else if (kY_SkAxisAlignment == baseline) { fxMask = 0; halfSampleX = SK_ScalarHalf; } } else { halfSampleX = halfSampleY = SK_ScalarHalf; } Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX); Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY); // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix, but for // performance reasons we just invert here instead if (!viewMatrix.invert(&fLocalMatrix)) { SkDebugf("Cannot invert viewmatrix\n"); return; } while (text < stop) { const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); fx += autokern.adjust(glyph); if (glyph.fWidth) { this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), glyph.getSubXFixed(), glyph.getSubYFixed(), GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), fontScaler); } fx += glyph.fAdvanceX; fy += glyph.fAdvanceY; } this->finish(); }
void GrBitmapTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, const SkPaint& skPaint, const SkMatrix& viewMatrix, const char text[], size_t byteLength, const SkScalar pos[], int scalarsPerPosition, const SkPoint& offset) { SkASSERT(byteLength == 0 || text != NULL); SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); // nothing to draw if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) { return; } this->init(rt, clip, paint, skPaint); SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &viewMatrix); SkGlyphCache* cache = autoCache.getCache(); GrFontScaler* fontScaler = GetGrFontScaler(cache); // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix, but for // performance reasons we just invert here instead if (!viewMatrix.invert(&fLocalMatrix)) { SkDebugf("Cannot invert viewmatrix\n"); return; } int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); fTotalVertexCount = kVerticesPerGlyph*numGlyphs; const char* stop = text + byteLength; SkTextAlignProc alignProc(fSkPaint.getTextAlign()); SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition); SkScalar halfSampleX = 0, halfSampleY = 0; if (cache->isSubpixel()) { // maybe we should skip the rounding if linearText is set SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix); SkFixed fxMask = ~0; SkFixed fyMask = ~0; if (kX_SkAxisAlignment == baseline) { fyMask = 0; halfSampleY = SK_ScalarHalf; } else if (kY_SkAxisAlignment == baseline) { fxMask = 0; halfSampleX = SK_ScalarHalf; } if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { while (text < stop) { SkPoint tmsLoc; tmsProc(pos, &tmsLoc); Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX); Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY); const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); if (glyph.fWidth) { this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), glyph.getSubXFixed(), glyph.getSubYFixed(), GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), fontScaler); } pos += scalarsPerPosition; } } else { while (text < stop) { const char* currentText = text; const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); if (metricGlyph.fWidth) { SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) SkPoint tmsLoc; tmsProc(pos, &tmsLoc); SkPoint alignLoc; alignProc(tmsLoc, metricGlyph, &alignLoc); Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX); Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY); // have to call again, now that we've been "aligned" const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, fx & fxMask, fy & fyMask); // the assumption is that the metrics haven't changed SkASSERT(prevAdvX == glyph.fAdvanceX); SkASSERT(prevAdvY == glyph.fAdvanceY); SkASSERT(glyph.fWidth); this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), glyph.getSubXFixed(), glyph.getSubYFixed(), GrGlyph::kCoverage_MaskStyle), Sk48Dot16FloorToInt(fx), Sk48Dot16FloorToInt(fy), fontScaler); }