SkRect FindCanvas::addMatchPos(int index, const SkPaint& paint, int count, const uint16_t* glyphs, const SkScalar xPos[], SkScalar /* y */) { SkRect r; r.setEmpty(); const SkPoint* temp = reinterpret_cast<const SkPoint*> (xPos); const SkPoint* points = &temp[index]; int countInBytes = count * sizeof(uint16_t); SkPaint::FontMetrics fontMetrics; paint.getFontMetrics(&fontMetrics); // Need to check each character individually, since the heights may be // different. for (int j = 0; j < count; j++) { SkRect bounds; bounds.fLeft = points[j].fX; bounds.fRight = bounds.fLeft + paint.measureText(&glyphs[j], sizeof(uint16_t), 0); SkScalar baseline = points[j].fY; bounds.fTop = baseline + fontMetrics.fAscent; bounds.fBottom = baseline + fontMetrics.fDescent; /* Accumulate and then add the resulting rect to mMatches */ r.join(bounds); } SkMatrix matrix = getTotalMatrix(); matrix.mapRect(&r); SkCanvas* canvas = getWorkingCanvas(); int saveCount = canvas->save(); canvas->concat(matrix); canvas->drawPosText(glyphs, countInBytes, points, paint); canvas->restoreToCount(saveCount); return r; }
void GpuGMTask::draw(GrContextFactory* grFactory) { SkImageInfo info = SkImageInfo::Make(SkScalarCeilToInt(fGM->width()), SkScalarCeilToInt(fGM->height()), kN32_SkColorType, kPremul_SkAlphaType); SkAutoTUnref<SkSurface> surface(NewGpuSurface(grFactory, fContextType, fGpuAPI, info, fSampleCount)); if (!surface) { if (!gAlreadyWarned[fContextType][fGpuAPI]) { SkDebugf("FYI: couldn't create GPU context, type %d API %d. Will skip.\n", fContextType, fGpuAPI); gAlreadyWarned[fContextType][fGpuAPI] = true; } return; } SkCanvas* canvas = surface->getCanvas(); CanvasPreflight(canvas); canvas->concat(fGM->getInitialTransform()); fGM->draw(canvas); canvas->flush(); #if GR_CACHE_STATS && SK_SUPPORT_GPU if (FLAGS_veryVerbose) { grFactory->get(fContextType)->printCacheStats(); } #endif SkBitmap bitmap; bitmap.setInfo(info); canvas->readPixels(&bitmap, 0, 0); this->spawnChild(SkNEW_ARGS(WriteTask, (*this, "GM", bitmap))); }
SkRect FindCanvas::addMatchPosH(int index, const SkPaint& paint, int count, const uint16_t* glyphs, const SkScalar position[], SkScalar constY) { SkRect r; // We only care about the positions starting at the index of our match const SkScalar* xPos = &position[index]; // This assumes that the position array is monotonic increasing // The left bounds will be the position of the left most character r.fLeft = xPos[0]; // The right bounds will be the position of the last character plus its // width int lastIndex = count - 1; r.fRight = paint.measureText(&glyphs[lastIndex], sizeof(uint16_t), 0) + xPos[lastIndex]; // Grab font metrics to determine the top and bottom of the bounds SkPaint::FontMetrics fontMetrics; paint.getFontMetrics(&fontMetrics); r.fTop = constY + fontMetrics.fAscent; r.fBottom = constY + fontMetrics.fDescent; const SkMatrix& matrix = getTotalMatrix(); matrix.mapRect(&r); SkCanvas* canvas = getWorkingCanvas(); int saveCount = canvas->save(); canvas->concat(matrix); canvas->drawPosTextH(glyphs, count * sizeof(uint16_t), xPos, constY, paint); canvas->restoreToCount(saveCount); return r; }
static void render_picture(GrContext* grContext, int width, int height, const SkPicture* picture, const SkMatrix& matrix) { SkASSERT(grContext); if (!picture) { SkDebugf(TAG "!picture\n"); return; } // Render to the default framebuffer render target. GrBackendRenderTargetDesc desc; desc.fWidth = width; desc.fHeight = height; desc.fConfig = kSkia8888_GrPixelConfig; desc.fOrigin = kBottomLeft_GrSurfaceOrigin; SkSurfaceProps surfaceProps(SkSurfaceProps::kUseDeviceIndependentFonts_Flag, kUnknown_SkPixelGeometry); // TODO: Check to see if we can keep the surface between draw calls. SkAutoTUnref<SkSurface> surface( SkSurface::NewFromBackendRenderTarget( grContext, desc, &surfaceProps)); if (surface) { SkCanvas* canvas = surface->getCanvas(); SkASSERT(canvas); canvas->clear(SK_ColorGRAY); canvas->concat(matrix); SkRect cullRect = picture->cullRect(); canvas->clipRect(cullRect); picture->playback(canvas); canvas->flush(); } }
static void test_discarded_image(skiatest::Reporter* reporter, const SkMatrix& transform, sk_sp<SkImage> (*buildImage)()) { auto surface(SkSurface::MakeRasterN32Premul(10, 10)); SkCanvas* canvas = surface->getCanvas(); // SkBitmapCache is global, so other threads could be evicting our bitmaps. Loop a few times // to mitigate this risk. const unsigned kRepeatCount = 42; for (unsigned i = 0; i < kRepeatCount; ++i) { SkAutoCanvasRestore acr(canvas, true); sk_sp<SkImage> image(buildImage()); // always use high quality to ensure caching when scaled SkPaint paint; paint.setFilterQuality(kHigh_SkFilterQuality); // draw the image (with a transform, to tickle different code paths) to ensure // any associated resources get cached canvas->concat(transform); canvas->drawImage(image, 0, 0, &paint); const auto desc = SkBitmapCacheDesc::Make(image.get()); // delete the image image.reset(nullptr); // all resources should have been purged SkBitmap result; REPORTER_ASSERT(reporter, !SkBitmapCache::Find(desc, &result)); } }
// Each version of addMatch returns a rectangle for a match. // Not all of the parameters are used by each version. SkRect FindCanvas::addMatchNormal(int index, const SkPaint& paint, int count, const uint16_t* glyphs, const SkScalar pos[], SkScalar y) { const uint16_t* lineStart = glyphs - index; /* Use the original paint, since "text" is in glyphs */ SkScalar before = paint.measureText(lineStart, index * sizeof(uint16_t), 0); SkRect rect; rect.fLeft = pos[0] + before; int countInBytes = count * sizeof(uint16_t); rect.fRight = paint.measureText(glyphs, countInBytes, 0) + rect.fLeft; SkPaint::FontMetrics fontMetrics; paint.getFontMetrics(&fontMetrics); SkScalar baseline = y; rect.fTop = baseline + fontMetrics.fAscent; rect.fBottom = baseline + fontMetrics.fDescent; const SkMatrix& matrix = getTotalMatrix(); matrix.mapRect(&rect); // Add the text to our picture. SkCanvas* canvas = getWorkingCanvas(); int saveCount = canvas->save(); canvas->concat(matrix); canvas->drawText(glyphs, countInBytes, pos[0] + before, y, paint); canvas->restoreToCount(saveCount); return rect; }
SkPicture* RecordPicture(skiagm::GM* gm, uint32_t recordFlags, SkBBHFactory* factory) { const SkISize size = gm->getISize(); SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(size.width(), size.height(), factory, recordFlags); canvas->concat(gm->getInitialTransform()); gm->draw(canvas); canvas->flush(); return recorder.endRecording(); }
void View::draw(SkCanvas & canvas) { SkAutoCanvasRestore restore(&canvas, true); canvas.concat(m_props.matrix()); canvas.clipRect(m_props.localRect(), SkRegion::kIntersect_Op, true); onDraw(canvas); for (View* v : m_children) { v->draw(canvas); } }
void GrLayerHoister::DrawLayersToAtlas(GrContext* context, const SkTDArray<GrHoistedLayer>& atlased) { if (atlased.count() > 0) { // All the atlased layers are rendered into the same GrTexture SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( atlased[0].fLayer->texture()->asRenderTarget(), NULL)); SkCanvas* atlasCanvas = surface->getCanvas(); SkPaint clearPaint; clearPaint.setColor(SK_ColorTRANSPARENT); clearPaint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref(); for (int i = 0; i < atlased.count(); ++i) { const GrCachedLayer* layer = atlased[i].fLayer; const SkPicture* pict = atlased[i].fPicture; const SkIPoint offset = atlased[i].fOffset; SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();) SkASSERT(!layerPaint || !layerPaint->getImageFilter()); atlasCanvas->save(); // Add a rect clip to make sure the rendering doesn't // extend beyond the boundaries of the atlased sub-rect SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft), SkIntToScalar(layer->rect().fTop), SkIntToScalar(layer->rect().width()), SkIntToScalar(layer->rect().height())); atlasCanvas->clipRect(bound); // Since 'clear' doesn't respect the clip we need to draw a rect atlasCanvas->drawRect(bound, clearPaint); // '-offset' maps the layer's top/left to the origin. // Since this layer is atlased, the top/left corner needs // to be offset to the correct location in the backing texture. SkMatrix initialCTM; initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); initialCTM.preTranslate(bound.fLeft, bound.fTop); initialCTM.preConcat(atlased[i].fPreMat); atlasCanvas->setMatrix(initialCTM); atlasCanvas->concat(atlased[i].fLocalMat); SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas, bound, layer->start() + 1, layer->stop(), initialCTM); atlasCanvas->restore(); } atlasCanvas->flush(); }
bool SkWindow::update(SkIRect* updateArea) { if (!fDirtyRgn.isEmpty()) { SkBitmap bm = this->getBitmap(); #if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN) char* buffer = (char*)GXBeginDraw(); SkASSERT(buffer); RECT rect; GetWindowRect((HWND)((SkOSWindow*)this)->getHWND(), &rect); buffer += rect.top * gDisplayProps.cbyPitch + rect.left * gDisplayProps.cbxPitch; bm.setPixels(buffer); #endif SkAutoTUnref<SkSurface> surface(this->createSurface()); SkCanvas* canvas = surface->getCanvas(); canvas->clipRegion(fDirtyRgn); if (updateArea) *updateArea = fDirtyRgn.getBounds(); SkAutoCanvasRestore acr(canvas, true); canvas->concat(fMatrix); // empty this now, so we can correctly record any inval calls that // might be made during the draw call. fDirtyRgn.setEmpty(); #ifdef SK_SIMULATE_FAILED_MALLOC gEnableControlledThrow = true; #endif #ifdef SK_BUILD_FOR_WIN32 //try { this->draw(canvas); //} //catch (...) { //} #else this->draw(canvas); #endif #ifdef SK_SIMULATE_FAILED_MALLOC gEnableControlledThrow = false; #endif #if defined(SK_BUILD_FOR_WINCE) && defined(USE_GX_SCREEN) GXEndDraw(); #endif return true; } return false; }
void OsmAnd::MapRasterizer_P::rasterizePolylineIcons( const Context& context, SkCanvas& canvas, const SkPath& path, const MapStyleEvaluationResult& evalResult) { bool ok; QString pathIconName; ok = evalResult.getStringValue(context.env->styleBuiltinValueDefs->id_OUTPUT_PATH_ICON, pathIconName); if (!ok || pathIconName.isEmpty()) return; float pathIconStep = 0.0f; ok = evalResult.getFloatValue(context.env->styleBuiltinValueDefs->id_OUTPUT_PATH_ICON_STEP, pathIconStep); if (!ok || pathIconStep <= 0.0f) return; std::shared_ptr<const SkBitmap> pathIcon; ok = context.env->obtainMapIcon(pathIconName, pathIcon); if (!ok || !pathIcon) return; SkMatrix mIconTransform; mIconTransform.setIdentity(); mIconTransform.setTranslate(-0.5f * pathIcon->width(), -0.5f * pathIcon->height()); mIconTransform.postRotate(90.0f); SkPathMeasure pathMeasure(path, false); const auto length = pathMeasure.getLength(); auto iconOffset = 0.5f * pathIconStep; const auto iconInstancesCount = static_cast<int>((length - iconOffset) / pathIconStep) + 1; if (iconInstancesCount < 1) return; SkMatrix mIconInstanceTransform; for (auto iconInstanceIdx = 0; iconInstanceIdx < iconInstancesCount; iconInstanceIdx++, iconOffset += pathIconStep) { SkMatrix mPinPoint; ok = pathMeasure.getMatrix(iconOffset, &mPinPoint); if (!ok) break; mIconInstanceTransform.setConcat(mPinPoint, mIconTransform); canvas.save(); canvas.concat(mIconInstanceTransform); canvas.drawBitmap(*pathIcon, 0, 0, &_defaultPaint); canvas.restore(); } }
void GrLayerHoister::DrawLayersToAtlas(GrContext* context, const SkTDArray<GrHoistedLayer>& atlased) { if (atlased.count() > 0) { // All the atlased layers are rendered into the same GrTexture SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( atlased[0].fLayer->texture()->asRenderTarget(), &props)); SkCanvas* atlasCanvas = surface->getCanvas(); for (int i = 0; i < atlased.count(); ++i) { const GrCachedLayer* layer = atlased[i].fLayer; const SkBigPicture* pict = atlased[i].fPicture->asSkBigPicture(); if (!pict) { // TODO: can we assume / assert this? continue; } const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop); SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();) SkASSERT(!layerPaint || !layerPaint->getImageFilter()); SkASSERT(!layer->filter()); atlasCanvas->save(); // Add a rect clip to make sure the rendering doesn't // extend beyond the boundaries of the atlased sub-rect const SkRect bound = SkRect::Make(layer->rect()); atlasCanvas->clipRect(bound); atlasCanvas->clear(0); // '-offset' maps the layer's top/left to the origin. // Since this layer is atlased, the top/left corner needs // to be offset to the correct location in the backing texture. SkMatrix initialCTM; initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); initialCTM.preTranslate(bound.fLeft, bound.fTop); initialCTM.preConcat(atlased[i].fPreMat); atlasCanvas->setMatrix(initialCTM); atlasCanvas->concat(atlased[i].fLocalMat); pict->partialPlayback(atlasCanvas, layer->start() + 1, layer->stop(), initialCTM); atlasCanvas->restore(); } atlasCanvas->flush(); }
static void test_sweep_fuzzer(skiatest::Reporter*) { static const SkColor gColors0[] = { 0x30303030, 0x30303030, 0x30303030 }; static const SkScalar gPos0[] = { -47919293023455565225163489280.0f, 0, 1 }; static const SkScalar gMatrix0[9] = { 1.12116716e-13f, 0 , 8.50489682e+16f, 4.1917041e-41f , 3.51369881e-23f, -2.54344271e-26f, 9.61111907e+17f, -3.35263808e-29f, -1.35659403e+14f }; static const struct { SkPoint fCenter; const SkColor* fColors; const SkScalar* fPos; int fCount; const SkScalar* fGlobalMatrix; } gConfigs[] = { { { 0, 0 }, gColors0, gPos0, SK_ARRAY_COUNT(gColors0), gMatrix0 }, }; sk_sp<SkSurface> surface = SkSurface::MakeRasterN32Premul(100, 100); SkCanvas* canvas = surface->getCanvas(); SkPaint paint; for (const auto& config : gConfigs) { paint.setShader(SkGradientShader::MakeSweep(config.fCenter.x(), config.fCenter.y(), config.fColors, config.fPos, config.fCount)); SkAutoCanvasRestore acr(canvas, false); if (config.fGlobalMatrix) { SkMatrix m; m.set9(config.fGlobalMatrix); canvas->save(); canvas->concat(m); } canvas->drawPaint(paint); } }
static void DrawRoundRect(SkCanvas& canvas) { bool ret = false; SkPaint paint; SkBitmap bitmap; SkMatrix matrix; matrix.reset(); bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1370, 812); bitmap.allocPixels(); #if 0 SkCanvas canvas; canvas.setBitmapDevice(bitmap); #endif // set up clipper SkRect skclip; skclip.set(SkIntToScalar(284), SkIntToScalar(40), SkIntToScalar(1370), SkIntToScalar(708)); // ret = canvas.clipRect(skclip); // SkASSERT(ret); matrix.set(SkMatrix::kMTransX, SkFloatToScalar(-1153.28f)); matrix.set(SkMatrix::kMTransY, SkFloatToScalar(1180.50f)); matrix.set(SkMatrix::kMScaleX, SkFloatToScalar(0.177171f)); matrix.set(SkMatrix::kMScaleY, SkFloatToScalar(0.177043f)); matrix.set(SkMatrix::kMSkewX, SkFloatToScalar(0.126968f)); matrix.set(SkMatrix::kMSkewY, SkFloatToScalar(-0.126876f)); matrix.set(SkMatrix::kMPersp0, SkFloatToScalar(0.0f)); matrix.set(SkMatrix::kMPersp1, SkFloatToScalar(0.0f)); ret = canvas.concat(matrix); paint.setAntiAlias(true); paint.setColor(0xb2202020); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkFloatToScalar(68.13f)); SkRect r; r.set(SkFloatToScalar(-313.714417f), SkFloatToScalar(-4.826389f), SkFloatToScalar(18014.447266f), SkFloatToScalar(1858.154541f)); canvas.drawRoundRect(r, SkFloatToScalar(91.756363f), SkFloatToScalar(91.756363f), paint); }
static void DrawRoundRect() { #ifdef SK_SCALAR_IS_FIXED bool ret = false; SkPaint paint; SkBitmap bitmap; SkCanvas canvas; SkMatrix matrix; matrix.reset(); bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1370, 812); bitmap.allocPixels(); canvas.setBitmapDevice(bitmap); // set up clipper SkRect skclip; skclip.set(SkIntToFixed(284), SkIntToFixed(40), SkIntToFixed(1370), SkIntToFixed(708)); ret = canvas.clipRect(skclip); SkASSERT(ret); matrix.set(SkMatrix::kMTransX, SkFloatToFixed(-1153.28)); matrix.set(SkMatrix::kMTransY, SkFloatToFixed(1180.50)); matrix.set(SkMatrix::kMScaleX, SkFloatToFixed(0.177171)); matrix.set(SkMatrix::kMScaleY, SkFloatToFixed(0.177043)); matrix.set(SkMatrix::kMSkewX, SkFloatToFixed(0.126968)); matrix.set(SkMatrix::kMSkewY, SkFloatToFixed(-0.126876)); matrix.set(SkMatrix::kMPersp0, SkFloatToFixed(0.0)); matrix.set(SkMatrix::kMPersp1, SkFloatToFixed(0.0)); ret = canvas.concat(matrix); paint.setAntiAlias(true); paint.setColor(0xb2202020); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkFloatToFixed(68.13)); SkRect r; r.set(SkFloatToFixed(-313.714417), SkFloatToFixed(-4.826389), SkFloatToFixed(18014.447266), SkFloatToFixed(1858.154541)); canvas.drawRoundRect(r, SkFloatToFixed(91.756363), SkFloatToFixed(91.756363), paint); #endif }
void GpuGMTask::draw(GrContextFactory* grFactory) { SkImageInfo info = SkImageInfo::Make(SkScalarCeilToInt(fGM->width()), SkScalarCeilToInt(fGM->height()), kPMColor_SkColorType, kPremul_SkAlphaType); SkAutoTUnref<SkSurface> surface(NewGpuSurface(grFactory, fContextType, info, fSampleCount)); SkCanvas* canvas = surface->getCanvas(); canvas->concat(fGM->getInitialTransform()); fGM->draw(canvas); canvas->flush(); SkBitmap bitmap; bitmap.setConfig(info); canvas->readPixels(&bitmap, 0, 0); this->spawnChild(SkNEW_ARGS(ExpectationsTask, (*this, fExpectations, bitmap))); this->spawnChild(SkNEW_ARGS(WriteTask, (*this, bitmap))); }
void copyMinToMax() { erase(fMaxSurface); SkCanvas* canvas = fMaxSurface->getCanvas(); canvas->save(); canvas->concat(fMatrix); fMinSurface->draw(canvas, 0, 0, NULL); canvas->restore(); SkPaint paint; paint.setXfermodeMode(SkXfermode::kClear_Mode); for (int iy = 1; iy < fH; ++iy) { SkScalar y = SkIntToScalar(iy * fZoom); canvas->drawLine(0, y - SK_ScalarHalf, 999, y - SK_ScalarHalf, paint); } for (int ix = 1; ix < fW; ++ix) { SkScalar x = SkIntToScalar(ix * fZoom); canvas->drawLine(x - SK_ScalarHalf, 0, x - SK_ScalarHalf, 999, paint); } }
void PipeTask::draw() { SkBitmap bitmap; SetupBitmap(fReference.config(), fGM.get(), &bitmap); SkCanvas canvas(bitmap); PipeController pipeController(&canvas, &SkImageDecoder::DecodeMemory); SkGPipeWriter writer; SkCanvas* pipeCanvas = writer.startRecording(&pipeController, fFlags, bitmap.width(), bitmap.height()); pipeCanvas->concat(fGM->getInitialTransform()); fGM->draw(pipeCanvas); writer.endRecording(); if (!BitmapsEqual(bitmap, fReference)) { this->fail(); this->spawnChild(SkNEW_ARGS(WriteTask, (*this, bitmap))); } }
PassRefPtr<SkImage> DragImage::resizeAndOrientImage(PassRefPtr<SkImage> image, ImageOrientation orientation, FloatSize imageScale, float opacity, InterpolationQuality interpolationQuality) { IntSize size(image->width(), image->height()); size.scale(imageScale.width(), imageScale.height()); AffineTransform transform; if (orientation != DefaultImageOrientation) { if (orientation.usesWidthAsHeight()) size = size.transposedSize(); transform *= orientation.transformFromDefault(size); } transform.scaleNonUniform(imageScale.width(), imageScale.height()); if (size.isEmpty()) return nullptr; if (transform.isIdentity() && opacity == 1) { // Nothing to adjust, just use the original. ASSERT(image->width() == size.width()); ASSERT(image->height() == size.height()); return image; } RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterN32Premul(size.width(), size.height())); if (!surface) return nullptr; SkPaint paint; ASSERT(opacity >= 0 && opacity <= 1); paint.setAlpha(opacity * 255); paint.setFilterQuality(interpolationQuality == InterpolationNone ? kNone_SkFilterQuality : kHigh_SkFilterQuality); SkCanvas* canvas = surface->getCanvas(); canvas->clear(SK_ColorTRANSPARENT); canvas->concat(affineTransformToSkMatrix(transform)); canvas->drawImage(image.get(), 0, 0, &paint); return adoptRef(surface->newImageSnapshot()); }
bool SkWindow::update(SkIRect* updateArea) { if (!fDirtyRgn.isEmpty()) { SkAutoTUnref<SkSurface> surface(this->createSurface()); SkCanvas* canvas = surface->getCanvas(); canvas->clipRegion(fDirtyRgn); if (updateArea) { *updateArea = fDirtyRgn.getBounds(); } SkAutoCanvasRestore acr(canvas, true); canvas->concat(fMatrix); // empty this now, so we can correctly record any inval calls that // might be made during the draw call. fDirtyRgn.setEmpty(); #ifdef SK_SIMULATE_FAILED_MALLOC gEnableControlledThrow = true; #endif #ifdef SK_BUILD_FOR_WIN32 //try { this->draw(canvas); //} //catch (...) { //} #else this->draw(canvas); #endif #ifdef SK_SIMULATE_FAILED_MALLOC gEnableControlledThrow = false; #endif return true; } return false; }
virtual void onDraw(SkCanvas* inputCanvas) override { SkScalar textSizes[] = { 9.0f, 9.0f*2.0f, 9.0f*5.0f, 9.0f*2.0f*5.0f }; SkScalar scales[] = { 2.0f*5.0f, 5.0f, 2.0f, 1.0f }; // set up offscreen rendering with distance field text GrContext* ctx = inputCanvas->getGrContext(); SkISize size = onISize(); SkImageInfo info = SkImageInfo::MakeN32(size.width(), size.height(), kPremul_SkAlphaType, inputCanvas->imageInfo().refColorSpace()); SkSurfaceProps props(SkSurfaceProps::kUseDeviceIndependentFonts_Flag, SkSurfaceProps::kLegacyFontHost_InitType); auto surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kNo, info, 0, &props)); SkCanvas* canvas = surface ? surface->getCanvas() : inputCanvas; // init our new canvas with the old canvas's matrix canvas->setMatrix(inputCanvas->getTotalMatrix()); // apply global scale to test glyph positioning canvas->scale(1.05f, 1.05f); canvas->clear(0xffffffff); SkPaint paint; paint.setAntiAlias(true); SkFont font(ToolUtils::create_portable_typeface("serif", SkFontStyle())); font.setSubpixel(true); const char* text = "Hamburgefons"; const size_t textLen = strlen(text); // check scaling up SkScalar x = SkIntToScalar(0); SkScalar y = SkIntToScalar(78); for (size_t i = 0; i < SK_ARRAY_COUNT(textSizes); ++i) { SkAutoCanvasRestore acr(canvas, true); canvas->translate(x, y); canvas->scale(scales[i], scales[i]); font.setSize(textSizes[i]); canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint); y += font.getMetrics(nullptr)*scales[i]; } // check rotation for (size_t i = 0; i < 5; ++i) { SkScalar rotX = SkIntToScalar(10); SkScalar rotY = y; SkAutoCanvasRestore acr(canvas, true); canvas->translate(SkIntToScalar(10 + i * 200), -80); canvas->rotate(SkIntToScalar(i * 5), rotX, rotY); for (int ps = 6; ps <= 32; ps += 3) { font.setSize(SkIntToScalar(ps)); canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, rotX, rotY, font, paint); rotY += font.getMetrics(nullptr); } } // check scaling down font.setEdging(SkFont::Edging::kSubpixelAntiAlias); x = SkIntToScalar(680); y = SkIntToScalar(20); size_t arraySize = SK_ARRAY_COUNT(textSizes); for (size_t i = 0; i < arraySize; ++i) { SkAutoCanvasRestore acr(canvas, true); canvas->translate(x, y); SkScalar scaleFactor = SkScalarInvert(scales[arraySize - i - 1]); canvas->scale(scaleFactor, scaleFactor); font.setSize(textSizes[i]); canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint); y += font.getMetrics(nullptr)*scaleFactor; } // check pos text { SkAutoCanvasRestore acr(canvas, true); canvas->scale(2.0f, 2.0f); SkAutoTArray<SkGlyphID> glyphs(SkToInt(textLen)); int count = font.textToGlyphs(text, textLen, SkTextEncoding::kUTF8, glyphs.get(), textLen); SkAutoTArray<SkPoint> pos(count); font.setSize(textSizes[0]); font.getPos(glyphs.get(), count, pos.get(), {340, 75}); auto blob = SkTextBlob::MakeFromPosText(glyphs.get(), count * sizeof(SkGlyphID), pos.get(), font, SkTextEncoding::kGlyphID); canvas->drawTextBlob(blob, 0, 0, paint); } // check gamma-corrected blending const SkColor fg[] = { 0xFFFFFFFF, 0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0xFF000000, }; paint.setColor(0xFFF7F3F7); SkRect r = SkRect::MakeLTRB(670, 215, 820, 397); canvas->drawRect(r, paint); x = SkIntToScalar(680); y = SkIntToScalar(235); font.setSize(SkIntToScalar(19)); for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) { paint.setColor(fg[i]); canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, x, y, font, paint); y += font.getMetrics(nullptr); } paint.setColor(0xFF181C18); r = SkRect::MakeLTRB(820, 215, 970, 397); canvas->drawRect(r, paint); x = SkIntToScalar(830); y = SkIntToScalar(235); font.setSize(SkIntToScalar(19)); for (size_t i = 0; i < SK_ARRAY_COUNT(fg); ++i) { paint.setColor(fg[i]); canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, x, y, font, paint); y += font.getMetrics(nullptr); } // check skew { font.setEdging(SkFont::Edging::kAntiAlias); SkAutoCanvasRestore acr(canvas, true); canvas->skew(0.0f, 0.151515f); font.setSize(SkIntToScalar(32)); canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 745, 70, font, paint); } { font.setEdging(SkFont::Edging::kSubpixelAntiAlias); SkAutoCanvasRestore acr(canvas, true); canvas->skew(0.5f, 0.0f); font.setSize(SkIntToScalar(32)); canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 580, 125, font, paint); } // check perspective { font.setEdging(SkFont::Edging::kAntiAlias); SkAutoCanvasRestore acr(canvas, true); SkMatrix persp; persp.setAll(0.9839f, 0, 0, 0.2246f, 0.6829f, 0, 0.0002352f, -0.0003844f, 1); canvas->concat(persp); canvas->translate(1100, -295); font.setSize(37.5f); canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint); } { font.setSubpixel(false); font.setEdging(SkFont::Edging::kAlias); SkAutoCanvasRestore acr(canvas, true); SkMatrix persp; persp.setAll(0.9839f, 0, 0, 0.2246f, 0.6829f, 0, 0.0002352f, -0.0003844f, 1); canvas->concat(persp); canvas->translate(1075, -245); canvas->scale(375, 375); font.setSize(0.1f); canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, 0, 0, font, paint); } // check color emoji if (fEmojiTypeface) { SkFont emoiFont; emoiFont.setSubpixel(true); emoiFont.setTypeface(fEmojiTypeface); emoiFont.setSize(SkIntToScalar(19)); canvas->drawSimpleText(fEmojiText, strlen(fEmojiText), SkTextEncoding::kUTF8, 670, 90, emoiFont, paint); } // render offscreen buffer if (surface) { SkAutoCanvasRestore acr(inputCanvas, true); // since we prepended this matrix already, we blit using identity inputCanvas->resetMatrix(); inputCanvas->drawImage(surface->makeImageSnapshot().get(), 0, 0, nullptr); } }
// "Interesting" fuzzer values. static void test_linear_fuzzer(skiatest::Reporter*) { static const SkColor gColors0[] = { 0x30303030, 0x30303030 }; static const SkColor gColors1[] = { 0x30303030, 0x30303030, 0x30303030 }; static const SkScalar gPos1[] = { 0, 0, 1 }; static const SkScalar gMatrix0[9] = { 6.40969056e-10f, 0 , 6.40969056e-10f, 0 , 4.42539023e-39f, 6.40969056e-10f, 0 , 0 , 1 }; static const SkScalar gMatrix1[9] = { -2.75294113f , 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, -3.32810161e+24f, 6.40969056e-10f, 6.40969056e-10f, 0 }; static const SkScalar gMatrix2[9] = { 7.93481258e+17f, 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, 0.688235283f }; static const SkScalar gMatrix3[9] = { 1.89180674e+11f, 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, 6.40969056e-10f, 11276.0469f , 8.12524808e+20f }; static const struct { SkPoint fPts[2]; const SkColor* fColors; const SkScalar* fPos; int fCount; SkTileMode fTileMode; uint32_t fFlags; const SkScalar* fLocalMatrix; const SkScalar* fGlobalMatrix; } gConfigs[] = { { {{0, -2.752941f}, {0, 0}}, gColors0, nullptr, SK_ARRAY_COUNT(gColors0), SkTileMode::kClamp, 0, gMatrix0, nullptr }, { {{4.42539023e-39f, -4.42539023e-39f}, {9.78041162e-15f, 4.42539023e-39f}}, gColors1, gPos1, SK_ARRAY_COUNT(gColors1), SkTileMode::kClamp, 0, nullptr, gMatrix1 }, { {{4.42539023e-39f, 6.40969056e-10f}, {6.40969056e-10f, 1.49237238e-19f}}, gColors1, gPos1, SK_ARRAY_COUNT(gColors1), SkTileMode::kClamp, 0, nullptr, gMatrix2 }, { {{6.40969056e-10f, 6.40969056e-10f}, {6.40969056e-10f, -0.688235283f}}, gColors0, nullptr, SK_ARRAY_COUNT(gColors0), SkTileMode::kClamp, 0, gMatrix3, nullptr }, }; sk_sp<SkColorSpace> srgb = SkColorSpace::MakeSRGB(); SkColorSpace* colorSpaces[] = { nullptr, // hits the legacy gradient impl srgb.get(), // triggers 4f/raster-pipeline }; SkPaint paint; for (auto colorSpace : colorSpaces) { sk_sp<SkSurface> surface = SkSurface::MakeRaster(SkImageInfo::Make(100, 100, kN32_SkColorType, kPremul_SkAlphaType, sk_ref_sp(colorSpace))); SkCanvas* canvas = surface->getCanvas(); for (const auto& config : gConfigs) { SkAutoCanvasRestore acr(canvas, false); SkTLazy<SkMatrix> localMatrix; if (config.fLocalMatrix) { localMatrix.init(); localMatrix.get()->set9(config.fLocalMatrix); } paint.setShader(SkGradientShader::MakeLinear(config.fPts, config.fColors, config.fPos, config.fCount, config.fTileMode, config.fFlags, localMatrix.getMaybeNull())); if (config.fGlobalMatrix) { SkMatrix m; m.set9(config.fGlobalMatrix); canvas->save(); canvas->concat(m); } canvas->drawPaint(paint); } } }
void GrLayerHoister::DrawLayers(const SkTDArray<GrHoistedLayer>& atlased, const SkTDArray<GrHoistedLayer>& nonAtlased, const SkTDArray<GrHoistedLayer>& recycled, GrReplacements* replacements) { // Render the atlased layers that require it if (atlased.count() > 0) { // All the atlased layers are rendered into the same GrTexture SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( atlased[0].fLayer->texture()->asRenderTarget(), NULL)); SkCanvas* atlasCanvas = surface->getCanvas(); SkPaint paint; paint.setColor(SK_ColorTRANSPARENT); paint.setXfermode(SkXfermode::Create(SkXfermode::kSrc_Mode))->unref(); for (int i = 0; i < atlased.count(); ++i) { GrCachedLayer* layer = atlased[i].fLayer; const SkPicture* pict = atlased[i].fPicture; const SkIPoint offset = atlased[i].fOffset; atlasCanvas->save(); // Add a rect clip to make sure the rendering doesn't // extend beyond the boundaries of the atlased sub-rect SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft), SkIntToScalar(layer->rect().fTop), SkIntToScalar(layer->rect().width()), SkIntToScalar(layer->rect().height())); atlasCanvas->clipRect(bound); // Since 'clear' doesn't respect the clip we need to draw a rect // TODO: ensure none of the atlased layers contain a clear call! atlasCanvas->drawRect(bound, paint); // info.fCTM maps the layer's top/left to the origin. // Since this layer is atlased, the top/left corner needs // to be offset to the correct location in the backing texture. SkMatrix initialCTM; initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); initialCTM.postTranslate(bound.fLeft, bound.fTop); atlasCanvas->translate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); atlasCanvas->translate(bound.fLeft, bound.fTop); atlasCanvas->concat(atlased[i].fCTM); SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas, bound, layer->start()+1, layer->stop(), initialCTM); atlasCanvas->restore(); } atlasCanvas->flush(); } // Render the non-atlased layers that require it for (int i = 0; i < nonAtlased.count(); ++i) { GrCachedLayer* layer = nonAtlased[i].fLayer; const SkPicture* pict = nonAtlased[i].fPicture; const SkIPoint offset = nonAtlased[i].fOffset; // Each non-atlased layer has its own GrTexture SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( layer->texture()->asRenderTarget(), NULL)); SkCanvas* layerCanvas = surface->getCanvas(); // Add a rect clip to make sure the rendering doesn't // extend beyond the boundaries of the atlased sub-rect SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft), SkIntToScalar(layer->rect().fTop), SkIntToScalar(layer->rect().width()), SkIntToScalar(layer->rect().height())); layerCanvas->clipRect(bound); // TODO: still useful? layerCanvas->clear(SK_ColorTRANSPARENT); SkMatrix initialCTM; initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); layerCanvas->translate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); layerCanvas->concat(nonAtlased[i].fCTM); SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas, bound, layer->start()+1, layer->stop(), initialCTM); layerCanvas->flush(); } convert_layers_to_replacements(atlased, replacements); convert_layers_to_replacements(nonAtlased, replacements); convert_layers_to_replacements(recycled, replacements); }