RegionBench(int count, Proc proc, const char name[]) { fProc = proc; fName.printf("region_%s_%d", name, count); SkRandom rand; for (int i = 0; i < count; i++) { fA.op(randrect(rand), SkRegion::kXOR_Op); fB.op(randrect(rand), SkRegion::kXOR_Op); } }
RegionBench(void* param, int count, Proc proc, const char name[], int mul = 1) : INHERITED(param) { fProc = proc; fName.printf("region_%s_%d", name, count); fLoopMul = mul; SkRandom rand; for (int i = 0; i < count; i++) { fA.op(randrect(rand), SkRegion::kXOR_Op); fB.op(randrect(rand), SkRegion::kXOR_Op); } }
void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color) { if (paintingDisabled()) return; unsigned rectCount = rects.size(); if (!rectCount) return; SkRegion focusRingRegion; const SkScalar focusRingOutset = WebCoreFloatToSkScalar(0.5); for (unsigned i = 0; i < rectCount; i++) { SkIRect r = rects[i]; r.inset(-focusRingOutset, -focusRingOutset); focusRingRegion.op(r, SkRegion::kUnion_Op); } SkPath path; SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); paint.setColor(color.rgb()); paint.setStrokeWidth(focusRingOutset * 2); paint.setPathEffect(new SkCornerPathEffect(focusRingOutset * 2))->unref(); focusRingRegion.getBoundaryPath(&path); platformContext()->canvas()->drawPath(path, paint); }
void DefaultTapHighlight::paintContents(const GraphicsLayer*, GraphicsContext& c, GraphicsLayerPaintingPhase, const IntRect& /*inClip*/) { std::vector<Platform::IntRect> rects = m_region.rects(); Platform::IntRect rect = m_region.extents(); SkRegion overlayRegion; unsigned rectCount = m_region.numRects(); if (!rectCount) return; for (unsigned i = 0; i < rectCount; ++i) { Platform::IntRect rectToPaint = rects[i]; SkIRect r = SkIRect::MakeXYWH(rectToPaint.x(), rectToPaint.y(), rectToPaint.width(), rectToPaint.height()); overlayRegion.op(r, SkRegion::kUnion_Op); } SkPath pathToPaint; overlayRegion.getBoundaryPath(&pathToPaint); Path path(pathToPaint); c.save(); c.translate(-rect.x(), -rect.y()); // Draw tap highlight c.setFillColor(m_color, ColorSpaceDeviceRGB); c.fillPath(path); Color darker = Color(m_color.red(), m_color.green(), m_color.blue()); // Get rid of alpha. c.setStrokeColor(darker, ColorSpaceDeviceRGB); c.setStrokeThickness(1); c.strokePath(path); c.restore(); }
static jboolean Region_op2(JNIEnv* env, jobject, jlong dstHandle, jlong region1Handle, jlong region2Handle, jint op) { SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); const SkRegion* region1 = reinterpret_cast<SkRegion*>(region1Handle); const SkRegion* region2 = reinterpret_cast<SkRegion*>(region2Handle); bool result = dst->op(*region1, *region2, (SkRegion::Op)op); return boolTojboolean(result); }
void SkPageFlipper::inval(const SkRegion& rgn) { SkRegion r; r.setRect(0, 0, fWidth, fHeight); if (r.op(rgn, SkRegion::kIntersect_Op)) { fDirty1->op(r, SkRegion::kUnion_Op); } }
void RegionLayerDrawExtra::addHighlightRegion(const LayerAndroid* layer, const Vector<IntRect>& rects, const IntPoint& additionalOffset, const IntRect& clipRect) { if (rects.isEmpty()) return; int layerId = layer ? layer->uniqueId() : 0; SkRegion* region = m_highlightRegions.get(layerId); if (!region) { region = new SkRegion(); m_highlightRegions.set(layerId, region); } IntPoint offset = additionalOffset; WebViewCore::layerToAbsoluteOffset(layer, offset); for (size_t i = 0; i < rects.size(); i++) { IntRect r = rects.at(i); if (!clipRect.isEmpty()) { r.intersect(clipRect); if (r.isEmpty()) continue; // don't add it to the region } r.move(-offset.x(), -offset.y()); region->op(r.x(), r.y(), r.maxX(), r.maxY(), SkRegion::kUnion_Op); } }
void PicturePile::drawWithClipRecursive(SkCanvas* canvas, SkRegion& clipRegion, int index) { // TODO: Add some debug visualizations of this if (index < 0 || clipRegion.isEmpty()) return; PictureContainer& pc = m_pile[index]; IntRect intersection = clipRegion.getBounds(); intersection.intersect(pc.area); if (pc.picture && !intersection.isEmpty()) { // SAMSUNG CHANGE ++ : Animation GIF frame remain in Base Picture // As the previous logic : Base Picture draws picture already drawn by other pile due to only using RECT. // It uses PATH and RECT, both now. SkPath pathClip; clipRegion.getBoundaryPath(&pathClip); // SAMSUNG CHANGE -- clipRegion.op(intersection, SkRegion::kDifference_Op); drawWithClipRecursive(canvas, clipRegion, index - 1); int saved = canvas->save(); canvas->clipRect(intersection); canvas->clipPath(pathClip); // SAMSUNG CHANGE : Animation GIF frame remain in Base Picture canvas->translate(pc.area.x(), pc.area.y()); canvas->drawPicture(*pc.picture); canvas->restoreToCount(saved); } else drawWithClipRecursive(canvas, clipRegion, index - 1); }
void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) { if (paintingDisabled()) return; unsigned rectCount = rects.size(); if (!rectCount) return; SkRegion focusRingRegion; const int focusRingOutset = getFocusRingOutset(offset); for (unsigned i = 0; i < rectCount; i++) { SkIRect r = rects[i]; r.inset(-focusRingOutset, -focusRingOutset); focusRingRegion.op(r, SkRegion::kUnion_Op); } SkPath path; SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); paint.setColor(color.rgb()); focusRingRegion.getBoundaryPath(&path); drawOuterPath(platformContext(), path, paint, width); drawInnerPath(platformContext(), path, paint, width); }
static jboolean Region_op1(JNIEnv* env, jobject, jlong dstHandle, jobject rectObject, jlong regionHandle, jint op) { SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); SkIRect ir; GraphicsJNI::jrect_to_irect(env, rectObject, &ir); bool result = dst->op(ir, *region, (SkRegion::Op)op); return boolTojboolean(result); }
static jboolean Region_op0(JNIEnv* env, jobject, jlong dstHandle, jint left, jint top, jint right, jint bottom, jint op) { SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); SkIRect ir; ir.set(left, top, right, bottom); bool result = dst->op(ir, (SkRegion::Op)op); return boolTojboolean(result); }
// Scale the region by given scale and set the reuslt to the dst. // dest and src can be the same region instance. static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) { SkRegion tmp; SkRegion::Iterator iter(src); for (; !iter.done(); iter.next()) { SkIRect r; scale_rect(&r, iter.rect(), scale); tmp.op(r, SkRegion::kUnion_Op); } dst->swap(tmp); }
void SkCanvasStack::onClipRegion(const SkRegion& deviceRgn, SkClipOp op) { SkASSERT(fList.count() == fCanvasData.count()); for (int i = 0; i < fList.count(); ++i) { SkRegion tempRegion; deviceRgn.translate(-fCanvasData[i].origin.x(), -fCanvasData[i].origin.y(), &tempRegion); tempRegion.op(fCanvasData[i].requiredClip, SkRegion::kIntersect_Op); fList[i]->clipRegion(tempRegion, op); } this->SkCanvas::onClipRegion(deviceRgn, op); }
RegionContainBench(Proc proc, const char name[]) { fProc = proc; fName.printf("region_contains_%s", name); SkRandom rand; for (int i = 0; i < COUNT; i++) { fA.op(randrect(rand, i), SkRegion::kXOR_Op); } fB.setRect(0, 0, H, W); }
void GLExtras::drawCursorRings() { SkRegion region; for (size_t i = 0; i < m_ring->rings().size(); i++) { IntRect rect = m_ring->rings().at(i); if (i == 0) region.setRect(rect); else region.op(rect, SkRegion::kUnion_Op); } drawRegion(region, m_ring->m_isPressed, !m_ring->m_isButton, false); }
RegionContainBench(void* param, Proc proc, const char name[]) : INHERITED(param) { fProc = proc; fName.printf("region_contains_%s", name); SkRandom rand; for (int i = 0; i < COUNT; i++) { fA.op(randrect(rand, i), SkRegion::kXOR_Op); } fB.setRect(0, 0, H, W); fIsRendering = false; }
void SkConservativeClip::opIRect(const SkIRect& devRect, SkRegion::Op op) { if (SkRegion::kIntersect_Op == op) { if (!fBounds.intersect(devRect)) { fBounds.setEmpty(); } return; } // This may still create a complex region (which we would then take the bounds // Perhaps we should inline the op-logic directly to never create the rgn... SkRegion result; result.op(SkRegion(fBounds), SkRegion(devRect), op); fBounds = result.getBounds(); this->applyClipRestriction(op, &fBounds); }
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; }
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); }
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 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); }
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); }
static bool union_proc(SkRegion& a, SkRegion& b) { SkRegion result; return result.op(a, b, SkRegion::kUnion_Op); }
void TileGrid::drawGL(const IntRect& visibleContentArea, float opacity, const TransformationMatrix* transform, const Color* background) { m_area = computeTilesArea(visibleContentArea, m_scale); if (m_area.width() == 0 || m_area.height() == 0) return; float invScale = 1.0 / m_scale; const float tileWidth = TilesManager::tileWidth() * invScale; const float tileHeight = TilesManager::tileHeight() * invScale; int drawn = 0; SkRegion missingRegion; bool semiOpaqueBaseSurface = background ? (background->hasAlpha() && background->alpha() > 0) : false; if (semiOpaqueBaseSurface) { SkIRect totalArea = SkIRect::MakeXYWH(m_area.x(), m_area.y(), m_area.width(), m_area.height()); missingRegion = SkRegion(totalArea); } bool usePointSampling = TilesManager::instance()->shader()->usePointSampling(m_scale, transform); float minTileX = visibleContentArea.x() / tileWidth; float minTileY = visibleContentArea.y() / tileWidth; float maxTileWidth = visibleContentArea.maxX() / tileWidth; float maxTileHeight = visibleContentArea.maxY() / tileWidth; ALOGV("minTileX, minTileY, maxTileWidth, maxTileHeight %f, %f, %f %f", minTileX, minTileY, maxTileWidth, maxTileHeight); for (unsigned int i = 0; i < m_tiles.size(); i++) { Tile* tile = m_tiles[i]; bool tileInView = tile->isTileVisible(m_area); if (tileInView) { SkRect rect; rect.fLeft = tile->x() * tileWidth; rect.fTop = tile->y() * tileHeight; rect.fRight = rect.fLeft + tileWidth; rect.fBottom = rect.fTop + tileHeight; ALOGV("tile %p (layer tile: %d) %d,%d at scale %.2f vs %.2f [ready: %d] dirty: %d", tile, tile->isLayerTile(), tile->x(), tile->y(), tile->scale(), m_scale, tile->isTileReady(), tile->isDirty()); bool forceBaseBlending = background ? background->hasAlpha() : false; float left = std::max(minTileX - tile->x(), 0.0f); float top = std::max(minTileY - tile->y(), 0.0f); float right = std::min(maxTileWidth - tile->x(), 1.0f); float bottom = std::min(maxTileHeight - tile->y(), 1.0f); if (left > 1.0f || top > 1.0f || right < 0.0f || bottom < 0.0f) { ALOGE("Unexpected portion:left, top, right, bottom %f %f %f %f", left, top, right, bottom); left = 0.0f; top = 0.0f; right = 1.0f; bottom = 1.0f; } FloatRect fillPortion(left, top, right - left, bottom - top); bool success = tile->drawGL(opacity, rect, m_scale, transform, forceBaseBlending, usePointSampling, fillPortion); if (semiOpaqueBaseSurface && success) { // Cut the successful drawn tile area from the missing region. missingRegion.op(SkIRect::MakeXYWH(tile->x(), tile->y(), 1, 1), SkRegion::kDifference_Op); } if (tile->frontTexture()) drawn++; } // log tile information for base, high res tiles if (m_isBaseSurface && background) TilesManager::instance()->getProfiler()->nextTile(tile, invScale, tileInView); } // Draw missing Regions with blend turned on if (semiOpaqueBaseSurface) drawMissingRegion(missingRegion, opacity, background); ALOGV("TG %p drew %d tiles, scale %f", this, drawn, m_scale); }
bool Surface::tryUpdateSurface(Surface* oldSurface) { if (!needsTexture() || !oldSurface->needsTexture()) return false; // merge surfaces based on first layer ID if (getFirstLayer()->uniqueId() != oldSurface->getFirstLayer()->uniqueId()) return false; m_surfaceBacking = oldSurface->m_surfaceBacking; SkSafeRef(m_surfaceBacking); ALOGV("%p taking old SurfBack %p from surface %p, nt %d", this, m_surfaceBacking, oldSurface, oldSurface->needsTexture()); if (!m_surfaceBacking) { // no SurfBack to inval, so don't worry about it. return true; } SkRegion invalRegion; bool fullInval = false; if (singleLayer() && oldSurface->singleLayer()) { // both are single matching layers, simply apply inval SkRegion* layerInval = getFirstLayer()->getInvalRegion(); invalRegion = *layerInval; if (isBase()) { // the base layer paints outside it's content area to ensure the // viewport is convered, so fully invalidate all tiles if its size // changes to ensure no stale content remains LayerContent* newContent = getFirstLayer()->content(); LayerContent* oldContent = oldSurface->getFirstLayer()->content(); fullInval = newContent->width() != oldContent->width() || newContent->height() != oldContent->height(); } } else { fullInval = m_layers.size() != oldSurface->m_layers.size(); if (!fullInval) { for (unsigned int i = 0; i < m_layers.size(); i++) { if ((m_layers[i]->uniqueId() != oldSurface->m_layers[i]->uniqueId()) || (m_layers[i]->fullContentAreaMapped() != oldSurface->m_layers[i]->fullContentAreaMapped())) { // layer list has changed, fully invalidate // TODO: partially invalidate based on layer size/position fullInval = true; break; } else if (!m_layers[i]->getInvalRegion()->isEmpty()) { // merge layer inval - translate the layer's inval region into surface coordinates // TODO: handle scale/3d transform mapping FloatRect layerPos = m_layers[i]->fullContentAreaMapped(); m_layers[i]->getInvalRegion()->translate(layerPos.x(), layerPos.y()); invalRegion.op(*(m_layers[i]->getInvalRegion()), SkRegion::kUnion_Op); } } } } if (fullInval) invalRegion.setRect(-1e8, -1e8, 2e8, 2e8); m_surfaceBacking->markAsDirty(invalRegion); return true; }
static bool diffrectbig_proc(SkRegion& a, SkRegion& b) { SkRegion result; return result.op(a, a.getBounds(), SkRegion::kDifference_Op); }
static bool diff_proc(SkRegion& a, SkRegion& b) { SkRegion result; return result.op(a, b, SkRegion::kDifference_Op); }
static bool sect_proc(SkRegion& a, SkRegion& b) { SkRegion result; return result.op(a, b, SkRegion::kIntersect_Op); }
DEF_TEST(CanvasState_test_complex_clips, reporter) { const int WIDTH = 400; const int HEIGHT = 400; const int SPACER = 10; SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4); layerRect.inset(2*SPACER, 2*SPACER); SkIRect clipRect = layerRect; clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER); clipRect.outset(SPACER, SPACER); SkIRect regionBounds = clipRect; regionBounds.offset(clipRect.width() + (2*SPACER), 0); SkIRect regionInterior = regionBounds; regionInterior.inset(SPACER*3, SPACER*3); SkRegion clipRegion; clipRegion.setRect(regionBounds); clipRegion.op(regionInterior, SkRegion::kDifference_Op); const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op, SkRegion::kIntersect_Op, SkRegion::kReplace_Op, }; const SkCanvas::SaveLayerFlags flags[] = { static_cast<SkCanvas::SaveLayerFlags>(SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag), 0, static_cast<SkCanvas::SaveLayerFlags>(SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag), }; REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags)); bool (*drawFn)(SkCanvasState* state, int32_t l, int32_t t, int32_t r, int32_t b, int32_t clipOp, int32_t regionRects, int32_t* rectCoords); OpenLibResult openLibResult(reporter); if (openLibResult.handle() != nullptr) { *(void**) (&drawFn) = dlsym(openLibResult.handle(), "complex_clips_draw_from_canvas_state"); } else { drawFn = complex_clips_draw_from_canvas_state; } REPORTER_ASSERT(reporter, drawFn); if (!drawFn) { return; } SkBitmap bitmaps[2]; for (int i = 0; i < 2; ++i) { bitmaps[i].allocN32Pixels(WIDTH, HEIGHT); SkCanvas canvas(bitmaps[i]); canvas.drawColor(SK_ColorRED); SkRegion localRegion = clipRegion; SkPaint paint; paint.setAlpha(128); for (size_t j = 0; j < SK_ARRAY_COUNT(flags); ++j) { SkRect layerBounds = SkRect::Make(layerRect); canvas.saveLayer(SkCanvas::SaveLayerRec(&layerBounds, &paint, flags[j])); if (i) { SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas); REPORTER_ASSERT(reporter, state); SkRegion::Iterator iter(localRegion); SkTDArray<int32_t> rectCoords; for (; !iter.done(); iter.next()) { const SkIRect& rect = iter.rect(); *rectCoords.append() = rect.fLeft; *rectCoords.append() = rect.fTop; *rectCoords.append() = rect.fRight; *rectCoords.append() = rect.fBottom; } bool success = drawFn(state, clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, clipOps[j], rectCoords.count() / 4, rectCoords.begin()); REPORTER_ASSERT(reporter, success); SkCanvasStateUtils::ReleaseCanvasState(state); } else { complex_clips_draw(&canvas, clipRect.fLeft, clipRect.fTop, clipRect.fRight, clipRect.fBottom, clipOps[j], localRegion); } canvas.restore(); // translate the canvas and region for the next iteration canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER)))); localRegion.translate(0, 2*(layerRect.height() + SPACER)); } } // now we memcmp the two bitmaps REPORTER_ASSERT(reporter, bitmaps[0].getSize() == bitmaps[1].getSize()); REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(), bitmaps[1].getPixels(), bitmaps[0].getSize())); }