// Draw the match specified by region to the canvas. void FindOnPage::drawMatch(const SkRegion& region, SkCanvas* canvas, bool focused) { // For the match which has focus, use a filled paint. For the others, use // a stroked paint. if (focused) { m_findPaint.setStyle(SkPaint::kFill_Style); m_findBlurPaint.setStyle(SkPaint::kFill_Style); } else { m_findPaint.setStyle(SkPaint::kStroke_Style); m_findPaint.setStrokeWidth(SK_Scalar1); m_findBlurPaint.setStyle(SkPaint::kStroke_Style); m_findBlurPaint.setStrokeWidth(SkIntToScalar(2)); } // Find the path for the current match SkPath matchPath; region.getBoundaryPath(&matchPath); // Offset the path for a blurred shadow SkPath blurPath; matchPath.offset(SK_Scalar1, SkIntToScalar(2), &blurPath); int saveCount = 0; if (!focused) { saveCount = canvas->save(); canvas->clipPath(matchPath, SkRegion::kDifference_Op); } // Draw the blurred background canvas->drawPath(blurPath, m_findBlurPaint); if (!focused) canvas->restoreToCount(saveCount); // Draw the foreground canvas->drawPath(matchPath, m_findPaint); }
bool SkMaskFilter::filterPath(const SkPath& devPath, const SkMatrix& matrix, const SkRegion& clip, SkBounder* bounder, SkBlitter* blitter) { SkMask srcM, dstM; if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), this, &matrix, &srcM, SkMask::kComputeBoundsAndRenderImage_CreateMode)) { return false; } SkAutoMaskFreeImage autoSrc(srcM.fImage); if (!this->filterMask(&dstM, srcM, matrix, NULL)) { return false; } SkAutoMaskFreeImage autoDst(dstM.fImage); SkRegion::Cliperator clipper(clip, dstM.fBounds); if (!clipper.done() && (bounder == NULL || bounder->doIRect(dstM.fBounds))) { const SkIRect& cr = clipper.rect(); do { blitter->blitMask(dstM, cr); clipper.next(); } while (!clipper.done()); } return true; }
static void setup_MC_state(SkMCState* state, const SkMatrix& matrix, const SkRegion& clip) { // initialize the struct state->clipRectCount = 0; // capture the matrix for (int i = 0; i < 9; i++) { state->matrix[i] = matrix.get(i); } /* * capture the clip * * storage is allocated on the stack for the first 4 rects. This value was * chosen somewhat arbitrarily, but does allow us to represent simple clips * and some more common complex clips (e.g. a clipRect with a sub-rect * clipped out of its interior) without needing to malloc any additional memory. */ SkSWriter32<4*sizeof(ClipRect)> clipWriter; if (!clip.isEmpty()) { // only returns the b/w clip so aa clips fail SkRegion::Iterator clip_iterator(clip); for (; !clip_iterator.done(); clip_iterator.next()) { // this assumes the SkIRect is stored in l,t,r,b ordering which // matches the ordering of our ClipRect struct clipWriter.writeIRect(clip_iterator.rect()); state->clipRectCount++; } } // allocate memory for the clip then and copy them to the struct state->clipRects = (ClipRect*) sk_malloc_throw(clipWriter.bytesWritten()); clipWriter.flatten(state->clipRects); }
static void test_pathregion() { SkPath path; SkRegion region; path.moveTo(25071800.f, -141823808.f); path.lineTo(25075500.f, -141824000.f); path.lineTo(25075400.f, -141827712.f); path.lineTo(25071810.f, -141827600.f); path.close(); SkIRect bounds; path.getBounds().round(&bounds); SkRegion clip(bounds); bool result = region.setPath(path, clip); // <-- !! DOWN !! SkDebugf("----- result %d\n", result); }
void SkPDFDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& region, const SkClipStack&) { // See the comment in the header file above GraphicStackEntry. if (region != fGraphicStack[fGraphicStackIndex].fClip) { while (fGraphicStackIndex > 0) popGS(); pushGS(); SkPath clipPath; if (region.getBoundaryPath(&clipPath)) { SkPDFUtils::EmitPath(clipPath, &fContent); SkPath::FillType clipFill = clipPath.getFillType(); NOT_IMPLEMENTED(clipFill == SkPath::kInverseEvenOdd_FillType, false); NOT_IMPLEMENTED(clipFill == SkPath::kInverseWinding_FillType, false); if (clipFill == SkPath::kEvenOdd_FillType) fContent.writeText("W* n "); else fContent.writeText("W n "); } fGraphicStack[fGraphicStackIndex].fClip = region; } setTransform(matrix); }
void Tile::markAsDirty(const SkRegion& dirtyArea) { if (dirtyArea.isEmpty()) return; android::AutoMutex lock(m_atomicSync); m_dirtyArea.op(dirtyArea, SkRegion::kUnion_Op); // Check if we actually intersect with the area bool intersect = false; SkRegion::Iterator cliperator(dirtyArea); SkRect realTileRect; SkRect dirtyRect; while (!cliperator.done()) { dirtyRect.set(cliperator.rect()); if (intersectWithRect(m_x, m_y, TilesManager::tileWidth(), TilesManager::tileHeight(), m_scale, dirtyRect, realTileRect)) { intersect = true; break; } cliperator.next(); } if (!intersect) return; markAsDirtyInternal(); }
DEF_TEST(FlattenableFactoryToName, r) { SkIRect rects[2]; rects[0] = SkIRect::MakeXYWH(0, 150, 500, 200); rects[1] = SkIRect::MakeXYWH(150, 0, 200, 500); SkRegion region; region.setRects(rects, 2); SkAutoTUnref<SkImageFilter> filter( SkAlphaThresholdFilter::Create(region, 0.2f, 0.7f)); test_flattenable(r, filter, "SkAlphaThresholdFilter()"); SkBitmap bm; bm.allocN32Pixels(8, 8); bm.eraseColor(SK_ColorCYAN); SkAutoTUnref<SkImage> image(SkImage::NewFromBitmap(bm)); auto shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode); test_flattenable(r, shader.get(), "SkImage::newShader()"); }
void GLWebViewState::setBaseLayer(BaseLayerAndroid* layer, const SkRegion& inval, bool showVisualIndicator, bool isPictureAfterFirstLayout) { if (!layer || isPictureAfterFirstLayout) { // TODO: move this into TreeManager m_zoomManager.swapPages(); // reset zoom state m_tiledPageA->discardTextures(); m_tiledPageB->discardTextures(); m_layersRenderingMode = kAllTextures; } if (layer) { XLOG("new base layer %p, (inval region empty %d) with child %p", layer, inval.isEmpty(), layer->getChild(0)); layer->setState(this); layer->markAsDirty(inval); // TODO: set in webview.cpp } m_treeManager.updateWithTree(layer, isPictureAfterFirstLayout); m_glExtras.setDrawExtra(0); #ifdef MEASURES_PERF if (m_measurePerfs && !showVisualIndicator) dumpMeasures(); m_measurePerfs = showVisualIndicator; #endif TilesManager::instance()->setShowVisualIndicator(showVisualIndicator); }
bool SkRasterClip::op(const SkPath& path, const SkISize& size, SkRegion::Op op, bool doAA) { // base is used to limit the size (and therefore memory allocation) of the // region that results from scan converting devPath. SkRegion base; if (fForceConservativeRects) { SkIRect ir; switch (mutate_conservative_op(&op, path.isInverseFillType())) { case kDoNothing_MutateResult: return !this->isEmpty(); case kReplaceClippedAgainstGlobalBounds_MutateResult: ir = SkIRect::MakeSize(size); break; case kContinue_MutateResult: ir = path.getBounds().roundOut(); break; } return this->op(ir, op); } if (SkRegion::kIntersect_Op == op) { // since we are intersect, we can do better (tighter) with currRgn's // bounds, than just using the device. However, if currRgn is complex, // our region blitter may hork, so we do that case in two steps. if (this->isRect()) { // FIXME: we should also be able to do this when this->isBW(), // but relaxing the test above triggers GM asserts in // SkRgnBuilder::blitH(). We need to investigate what's going on. return this->setPath(path, this->bwRgn(), doAA); } else { base.setRect(this->getBounds()); SkRasterClip clip(fForceConservativeRects); clip.setPath(path, base, doAA); return this->op(clip, op); } } else { base.setRect(0, 0, size.width(), size.height()); if (SkRegion::kReplace_Op == op) { return this->setPath(path, base, doAA); } else { SkRasterClip clip(fForceConservativeRects); clip.setPath(path, base, doAA); return this->op(clip, op); } } }
void SkPipeCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) { size_t size = region.writeToMemory(nullptr); unsigned extra = 0; if (fits_in(size, 24)) { extra = SkToUInt(size); } SkPipeWriter writer(this); writer.write32(pack_verb(SkPipeVerb::kDrawRegion, extra)); if (0 == extra) { writer.write32(size); } SkAutoSMalloc<2048> storage(size); region.writeToMemory(storage.get()); write_pad(&writer, storage.get(), size); write_paint(writer, paint, kGeometry_PaintUsage); }
bool SkPathContainsPoint(const SkPath& originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRect bounds = originalPath.getBounds(); // We can immediately return false if the point is outside the bounding // rect. We don't use bounds.contains() here, since it would exclude // points on the right and bottom edges of the bounding rect, and we want // to include them. SkScalar fX = SkFloatToScalar(point.x()); SkScalar fY = SkFloatToScalar(point.y()); if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) return false; // Scale the path to a large size before hit testing for two reasons: // 1) Skia has trouble with coordinates close to the max signed 16-bit values, so we scale larger paths down. // TODO: when Skia is patched to work properly with large values, this will not be necessary. // 2) Skia does not support analytic hit testing, so we scale paths up to do raster hit testing with subpixel accuracy. // 3) Scale the x/y axis separately so an extreme large/small scale factor on one axis won't // ruin the resolution of the other axis. SkScalar biggestCoordX = std::max(bounds.fRight, -bounds.fLeft); SkScalar biggestCoordY = std::max(bounds.fBottom, -bounds.fTop); if (SkScalarNearlyZero(biggestCoordX) || SkScalarNearlyZero(biggestCoordY)) return false; biggestCoordX = std::max(biggestCoordX, std::fabs(fX) + 1); biggestCoordY = std::max(biggestCoordY, std::fabs(fY) + 1); const SkScalar kMaxCoordinate = SkIntToScalar(1 << 15); SkScalar scaleX = kMaxCoordinate / biggestCoordX; SkScalar scaleY = kMaxCoordinate / biggestCoordY; SkRegion rgn; SkRegion clip; SkMatrix m; SkPath scaledPath(originalPath); scaledPath.setFillType(ft); m.setScale(scaleX, scaleY); scaledPath.transform(m, 0); int x = static_cast<int>(floorf(0.5f + point.x() * scaleX)); int y = static_cast<int>(floorf(0.5f + point.y() * scaleY)); clip.setRect(x - 1, y - 1, x + 1, y + 1); return rgn.setPath(scaledPath, clip); }
void SkGPipeCanvas::onClipRegion(const SkRegion& region, SkRegion::Op rgnOp) { NOTIFY_SETUP(this); if (this->needOpBytes(region.writeToMemory(nullptr))) { this->writeOp(kClipRegion_DrawOp, 0, rgnOp); fWriter.writeRegion(region); } this->INHERITED::onClipRegion(region, rgnOp); }
void SkPictureRecord::onDrawRegion(const SkRegion& region, const SkPaint& paint) { // op + paint index + region size_t regionBytes = region.writeToMemory(nullptr); size_t size = 2 * kUInt32Size + regionBytes; size_t initialOffset = this->addDraw(DRAW_REGION, &size); this->addPaint(paint); fWriter.writeRegion(region); this->validate(initialOffset, size); }
void drawPathOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) { SkRegion rgn; SkPath path; this->build_rgn(&rgn, op); rgn.getBoundaryPath(&path); this->drawOrig(canvas, true); SkPaint paint; paint.setStyle(SkPaint::kFill_Style); paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24)); canvas->drawPath(path, paint); paint.setColor(color); paint.setStyle(SkPaint::kStroke_Style); canvas->drawPath(path, paint); }
extern "C" bool complex_clips_draw_from_canvas_state(SkCanvasState* state, int32_t left, int32_t top, int32_t right, int32_t bottom, int32_t clipOp, int32_t regionRects, int32_t* rectCoords) { std::unique_ptr<SkCanvas> canvas = SkCanvasStateUtils::MakeFromCanvasState(state); if (!canvas) { return false; } SkRegion localRegion; for (int32_t i = 0; i < regionRects; ++i) { localRegion.op(rectCoords[0], rectCoords[1], rectCoords[2], rectCoords[3], SkRegion::kUnion_Op); rectCoords += 4; } complex_clips_draw(canvas.get(), left, top, right, bottom, clipOp, localRegion); return true; }
bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& devBounds, SkRegion::Op op, bool doAA) { AUTO_RASTERCLIP_VALIDATE(*this); SkIRect bounds(devBounds); this->applyClipRestriction(op, &bounds); // base is used to limit the size (and therefore memory allocation) of the // region that results from scan converting devPath. SkRegion base; SkPath devPath; if (matrix.isIdentity()) { devPath = path; } else { path.transform(matrix, &devPath); devPath.setIsVolatile(true); } if (SkRegion::kIntersect_Op == op) { // since we are intersect, we can do better (tighter) with currRgn's // bounds, than just using the device. However, if currRgn is complex, // our region blitter may hork, so we do that case in two steps. if (this->isRect()) { // FIXME: we should also be able to do this when this->isBW(), // but relaxing the test above triggers GM asserts in // SkRgnBuilder::blitH(). We need to investigate what's going on. return this->setPath(devPath, this->bwRgn(), doAA); } else { base.setRect(this->getBounds()); SkRasterClip clip; clip.setPath(devPath, base, doAA); return this->op(clip, op); } } else { base.setRect(bounds); if (SkRegion::kReplace_Op == op) { return this->setPath(devPath, base, doAA); } else { SkRasterClip clip; clip.setPath(devPath, base, doAA); return this->op(clip, op); } } }
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft) { SkRect bounds = originalPath->getBounds(); // We can immediately return false if the point is outside the bounding // rect. We don't use bounds.contains() here, since it would exclude // points on the right and bottom edges of the bounding rect, and we want // to include them. SkScalar fX = SkFloatToScalar(point.x()); SkScalar fY = SkFloatToScalar(point.y()); if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom) return false; // Scale the path to a large size before hit testing for two reasons: // 1) Skia has trouble with coordinates close to the max signed 16-bit values, so we scale larger paths down. // TODO: when Skia is patched to work properly with large values, this will not be necessary. // 2) Skia does not support analytic hit testing, so we scale paths up to do raster hit testing with subpixel accuracy. SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop); if (SkScalarNearlyZero(biggestCoord)) return false; biggestCoord = std::max(std::max(biggestCoord, fX + 1), fY + 1); const SkScalar kMaxCoordinate = SkIntToScalar(1 << 15); SkScalar scale = SkScalarDiv(kMaxCoordinate, biggestCoord); SkRegion rgn; SkRegion clip; SkMatrix m; SkPath scaledPath; SkPath::FillType originalFillType = originalPath->getFillType(); originalPath->setFillType(ft); m.setScale(scale, scale); originalPath->transform(m, &scaledPath); int x = static_cast<int>(floorf(0.5f + point.x() * scale)); int y = static_cast<int>(floorf(0.5f + point.y() * scale)); clip.setRect(x - 1, y - 1, x + 1, y + 1); bool contains = rgn.setPath(scaledPath, clip); originalPath->setFillType(originalFillType); return contains; }
void CursorRing::draw(SkCanvas* canvas, LayerAndroid* layer) { #if USE(ACCELERATED_COMPOSITING) int layerId = m_node->isInLayer() ? m_frame->layer(m_node)->uniqueId() : -1; if (layer->uniqueId() != layerId) return; #endif if (canvas->quickReject(m_bounds, SkCanvas::kAA_EdgeType)) { DBG_NAV_LOGD("canvas->quickReject cursorNode=%d (nodePointer=%p)" " bounds=(%d,%d,w=%d,h=%d)", m_node->index(), m_node->nodePointer(), m_bounds.x(), m_bounds.y(), m_bounds.width(), m_bounds.height()); m_followedLink = false; return; } unsigned rectCount = m_rings.size(); SkRegion rgn; SkPath path; for (unsigned i = 0; i < rectCount; i++) { SkRect r(m_rings[i]); SkIRect ir; r.round(&ir); ir.inset(-CURSOR_RING_OUTER_OUTSET, -CURSOR_RING_OUTER_OUTSET); rgn.op(ir, SkRegion::kUnion_Op); } rgn.getBoundaryPath(&path); SkPaint paint; paint.setAntiAlias(true); paint.setPathEffect(new SkCornerPathEffect(CURSOR_RING_ROUNDEDNESS))->unref(); if (m_flavor >= NORMAL_ANIMATING) { // pressed paint.setColor(cursorPressedColors[m_flavor - NORMAL_ANIMATING]); canvas->drawPath(path, paint); } paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(CURSOR_RING_OUTER_DIAMETER); paint.setColor(cursorOuterColors[m_flavor]); canvas->drawPath(path, paint); paint.setStrokeWidth(CURSOR_RING_INNER_DIAMETER); paint.setColor(cursorInnerColors[m_flavor]); canvas->drawPath(path, paint); }
void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect) { // rect is in the render object coordinates if (!m_image && !drawsContent()) { LOG("(%x) setNeedsDisplay(%.2f,%.2f,%.2f,%.2f) doesn't have content, bypass...", this, rect.x(), rect.y(), rect.width(), rect.height()); return; } SkRegion region; region.setRect(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height()); m_dirtyRegion.op(region, SkRegion::kUnion_Op); m_needsRepaint = true; askForSync(); }
virtual void recordCanvas(SkCanvas* canvas) { const SkPoint translateDelta = getTranslateDelta(); for (int i = 0; i < M; i++) { SkColor color = SK_ColorYELLOW + (i % 255); SkIRect rect = SkIRect::MakeWH(i,i); canvas->save(); // set the clip to the given region SkRegion region; region.setRect(rect); canvas->clipRegion(region); // fill the clip with a color SkPaint paint; paint.setColor(color); canvas->drawPaint(paint); // set a matrix on the canvas SkMatrix matrix; matrix.setRotate(SkIntToScalar(i % 360)); canvas->setMatrix(matrix); // create a simple bitmap SkBitmap bitmap; bitmap.setConfig(SkBitmap::kRGB_565_Config, 10, 10); bitmap.allocPixels(); // draw a single color into the bitmap SkCanvas bitmapCanvas(bitmap); bitmapCanvas.drawColor(SkColorSetA(color, i % 255)); // draw the bitmap onto the canvas canvas->drawBitmapMatrix(bitmap, matrix); canvas->restore(); canvas->translate(translateDelta.fX, translateDelta.fY); } }
void drawRgnOped(SkCanvas* canvas, SkRegion::Op op, SkColor color) { SkRegion rgn; this->build_rgn(&rgn, op); { SkRegion tmp, tmp2(rgn); tmp = tmp2; tmp.translate(5, -3); { char buffer[1000]; size_t size = tmp.flatten(NULL); SkASSERT(size <= sizeof(buffer)); size_t size2 = tmp.flatten(buffer); SkASSERT(size == size2); SkRegion tmp3; size2 = tmp3.unflatten(buffer); SkASSERT(size == size2); SkASSERT(tmp3 == tmp); } rgn.translate(20, 30, &tmp); SkASSERT(rgn.isEmpty() || tmp != rgn); tmp.translate(-20, -30); SkASSERT(tmp == rgn); } this->drawOrig(canvas, true); SkPaint paint; paint.setColor((color & ~(0xFF << 24)) | (0x44 << 24)); paint_rgn(canvas, rgn, paint); paint.setStyle(SkPaint::kStroke_Style); paint.setColor(color); paint_rgn(canvas, rgn, paint); }
static void setup_canvas_from_MC_state(const SkMCState& state, SkCanvas* canvas) { // reconstruct the matrix SkMatrix matrix; for (int i = 0; i < 9; i++) { matrix.set(i, state.matrix[i]); } // reconstruct the clip SkRegion clip; for (int i = 0; i < state.clipRectCount; ++i) { clip.op(SkIRect::MakeLTRB(state.clipRects[i].left, state.clipRects[i].top, state.clipRects[i].right, state.clipRects[i].bottom), SkRegion::kUnion_Op); } canvas->setMatrix(matrix); canvas->setClipRegion(clip); }
void updateMC(const SkMatrix& totalMatrix, const SkRegion& totalClip, const SkClipStack& clipStack, SkRegion* updateClip) { int x = fDevice->getOrigin().x(); int y = fDevice->getOrigin().y(); int width = fDevice->width(); int height = fDevice->height(); if ((x | y) == 0) { fMatrix = &totalMatrix; fClip = totalClip; } else { fMatrixStorage = totalMatrix; fMatrixStorage.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); fMatrix = &fMatrixStorage; totalClip.translate(-x, -y, &fClip); } fClip.op(0, 0, width, height, SkRegion::kIntersect_Op); // intersect clip, but don't translate it (yet) if (updateClip) { updateClip->op(x, y, x + width, y + height, SkRegion::kDifference_Op); } fDevice->setMatrixClip(*fMatrix, fClip, clipStack); #ifdef SK_DEBUG if (!fClip.isEmpty()) { SkIRect deviceR; deviceR.set(0, 0, width, height); SkASSERT(deviceR.contains(fClip.getBounds())); } #endif // default is to assume no external matrix fMVMatrix = NULL; fExtMatrix = NULL; }
void sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) { const SkIRect& cr = clip.getBounds(); SkIRect tmp; tmp.fLeft = cr.fLeft; tmp.fRight = cr.fRight; tmp.fTop = ir.fBottom; tmp.fBottom = cr.fBottom; if (!tmp.isEmpty()) { blitter->blitRectRegion(tmp, clip); } }
bool PathSkia::ContainsPoint(const Point &aPoint, const Matrix &aTransform) const { Matrix inverse = aTransform; inverse.Invert(); Point transformed = inverse * aPoint; Rect bounds = GetBounds(aTransform); if (aPoint.x < bounds.x || aPoint.y < bounds.y || aPoint.x > bounds.XMost() || aPoint.y > bounds.YMost()) { return false; } SkRegion pointRect; pointRect.setRect(SkFloatToScalar(transformed.x - 1), SkFloatToScalar(transformed.y - 1), SkFloatToScalar(transformed.x + 1), SkFloatToScalar(transformed.y + 1)); SkRegion pathRegion; return pathRegion.setPath(mPath, pointRect); }
static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) { // need to limit coordinates such that the width/height of our rect can be represented // in SkFixed (16.16). See skbug.com/7998 const int32_t limit = 32767 >> 1; SkIRect limitR; limitR.set(-limit, -limit, limit, limit); if (limitR.contains(orig.getBounds())) { return false; } reduced->op(orig, limitR, SkRegion::kIntersect_Op); return true; }
static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel) { if (parcel == nullptr) { return 0; } android::Parcel* p = android::parcelForJavaObject(env, parcel); std::vector<int32_t> rects; p->readInt32Vector(&rects); if ((rects.size() % 4) != 0) { return 0; } SkRegion* region = new SkRegion; for (size_t x = 0; x + 4 <= rects.size(); x += 4) { region->op(rects[x], rects[x+1], rects[x+2], rects[x+3], SkRegion::kUnion_Op); } return reinterpret_cast<jlong>(region); }
void createContent(int width, int height, Canvas& canvas) override { canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); canvas.insertReorderBarrier(true); card = TestUtils::createNode(50, 50, 250, 250, [](RenderProperties& props, Canvas& canvas) { canvas.drawColor(0xFFFF00FF, SkBlendMode::kSrcOver); SkRegion region; for (int xOffset = 0; xOffset < 200; xOffset += 2) { for (int yOffset = 0; yOffset < 200; yOffset += 2) { region.op(xOffset, yOffset, xOffset + 1, yOffset + 1, SkRegion::kUnion_Op); } } SkPaint paint; paint.setColor(0xff00ffff); canvas.drawRegion(region, paint); }); canvas.drawRenderNode(card.get()); canvas.insertReorderBarrier(false); }
DEFINE_BATCH_CLASS_ID RegionBatch(GrColor color, const SkMatrix& viewMatrix, const SkRegion& region) : INHERITED(ClassID()) , fViewMatrix(viewMatrix) { RegionInfo& info = fRegions.push_back(); info.fColor = color; info.fRegion = region; SkRect bounds = SkRect::Make(region.getBounds()); this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); }
// TODO: expand the testing to include the different ops & AA types! static void emit_clip(SkCanvas* canvas, ClipType clip) { switch (clip) { case kNone_ClipType: break; case kRect_ClipType: { SkRect r = SkRect::MakeLTRB(10, 10, 90, 90); canvas->clipRect(r, SkRegion::kIntersect_Op, true); break; } case kRRect_ClipType: { SkRect r = SkRect::MakeLTRB(10, 10, 90, 90); SkRRect rr; rr.setRectXY(r, 10, 10); canvas->clipRRect(rr, SkRegion::kIntersect_Op, true); break; } case kPath_ClipType: { SkPath p; p.moveTo(5.0f, 5.0f); p.lineTo(50.0f, 50.0f); p.lineTo(100.0f, 5.0f); p.close(); canvas->clipPath(p, SkRegion::kIntersect_Op, true); break; } case kRegion_ClipType: { SkIRect rects[2] = { { 1, 1, 55, 55 }, { 45, 45, 99, 99 }, }; SkRegion r; r.setRects(rects, 2); canvas->clipRegion(r, SkRegion::kIntersect_Op); break; } default: SkASSERT(0); } }