Example #1
0
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 (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;
            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;
            clip.setPath(path, base, doAA);
            return this->op(clip, op);
        }
    }
}
Example #2
0
bool SkRasterClip::op(const SkPath& path, const SkMatrix& matrix, const SkIRect& bounds,
                      SkRegion::Op op, bool doAA) {
    AUTO_RASTERCLIP_VALIDATE(*this);

    if (fForceConservativeRects) {
        SkIRect ir;
        switch (mutate_conservative_op(&op, path.isInverseFillType())) {
            case kDoNothing_MutateResult:
                return !this->isEmpty();
            case kReplaceClippedAgainstGlobalBounds_MutateResult:
                ir = bounds;
                break;
            case kContinue_MutateResult: {
                SkRect bounds = path.getBounds();
                matrix.mapRect(&bounds);
                ir = bounds.roundOut();
                break;
            }
        }
        return this->op(ir, op);
    }

    // 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(fForceConservativeRects);
            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(fForceConservativeRects);
            clip.setPath(devPath, base, doAA);
            return this->op(clip, op);
        }
    }
}
Example #3
0
bool
PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions,
                              const Point &aPoint,
                              const Matrix &aTransform) const
{
  Matrix inverse = aTransform;
  inverse.Invert();
  Point transformed = inverse * aPoint;

  SkPaint paint;
  StrokeOptionsToPaint(paint, aStrokeOptions);

  SkPath strokePath;
  paint.getFillPath(mPath, &strokePath);

  Rect bounds = aTransform.TransformBounds(SkRectToRect(strokePath.getBounds()));

  if (aPoint.x < bounds.x || aPoint.y < bounds.y ||
      aPoint.x > bounds.XMost() || aPoint.y > bounds.YMost()) {
    return false;
  }

  SkRegion pointRect;
  pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1.f)),
                    int32_t(SkFloatToScalar(transformed.y - 1.f)),
                    int32_t(SkFloatToScalar(transformed.x + 1.f)),
                    int32_t(SkFloatToScalar(transformed.y + 1.f)));

  SkRegion pathRegion;
  
  return pathRegion.setPath(strokePath, pointRect);
}
static BaseLayerAndroid* nativeDeserializeViewState(JNIEnv* env, jobject, jint version,
                                                    jobject jstream, jbyteArray jstorage)
{
    SkStream* stream = CreateJavaInputStreamAdaptor(env, jstream, jstorage);
    if (!stream)
        return 0;
    Color color = stream->readU32();
    SkPicture* picture = new SkPicture(stream);
    PictureLayerContent* content = new PictureLayerContent(picture);

    BaseLayerAndroid* layer = new BaseLayerAndroid(content);
    layer->setBackgroundColor(color);

    SkRegion dirtyRegion;
    dirtyRegion.setRect(0, 0, content->width(), content->height());
    layer->markAsDirty(dirtyRegion);

    SkSafeUnref(content);
    SkSafeUnref(picture);
    int childCount = stream->readS32();
    for (int i = 0; i < childCount; i++) {
        LayerAndroid* childLayer = deserializeLayer(version, stream);
        if (childLayer)
            layer->addChild(childLayer);
    }
    delete stream;
    return layer;
}
Example #5
0
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);
    }
}
Example #6
0
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);
        }
    }
}
Example #7
0
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);
        }
    }
}
void draw(SkCanvas* canvas) {
    SkRegion region;
    SkRegion::Iterator iter(region);
    auto r1 = iter.rect();
    SkDebugf("rect={%d,%d,%d,%d}\n", r1.fLeft, r1.fTop, r1.fRight, r1.fBottom);
    region.setRect({1, 2, 3, 4});
    iter.rewind();
    auto r2 = iter.rect();
    SkDebugf("rect={%d,%d,%d,%d}\n", r2.fLeft, r2.fTop, r2.fRight, r2.fBottom);
}
bool SkLayerRasterizer::onRasterize(const SkPath& path, const SkMatrix& matrix,
                                    const SkIRect* clipBounds,
                                    SkMask* mask, SkMask::CreateMode mode)
{
    if (fLayers.empty())
        return false;

    if (SkMask::kJustRenderImage_CreateMode != mode)
    {
        if (!compute_bounds(fLayers, path, matrix, clipBounds, &mask->fBounds))
            return false;
    }

    if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode)
    {
        mask->fFormat   = SkMask::kA8_Format;
        mask->fRowBytes = SkToU16(mask->fBounds.width());
        mask->fImage = SkMask::AllocImage(mask->computeImageSize());
        memset(mask->fImage, 0, mask->computeImageSize());
    }

    if (SkMask::kJustComputeBounds_CreateMode != mode)
    {    
        SkBitmap device;
        SkDraw   draw;
        SkMatrix translatedMatrix;  // this translates us to our local pixels
        SkMatrix drawMatrix;        // this translates the path by each layer's offset
        SkRegion rectClip;
        
        rectClip.setRect(0, 0, mask->fBounds.width(), mask->fBounds.height());

        translatedMatrix = matrix;
        translatedMatrix.postTranslate(-SkIntToScalar(mask->fBounds.fLeft),
                                       -SkIntToScalar(mask->fBounds.fTop));

        device.setConfig(SkBitmap::kA8_Config, mask->fBounds.width(), mask->fBounds.height(), mask->fRowBytes);
        device.setPixels(mask->fImage);

        draw.fBitmap    = &device;
        draw.fMatrix    = &drawMatrix;
        draw.fClip      = &rectClip;
        // we set the matrixproc in the loop, as the matrix changes each time (potentially)
        draw.fBounder   = NULL;
        
        SkDeque::Iter           iter(fLayers);
        SkLayerRasterizer_Rec*  rec;

        while ((rec = (SkLayerRasterizer_Rec*)iter.next()) != NULL) {
            drawMatrix = translatedMatrix;
            drawMatrix.preTranslate(rec->fOffset.fX, rec->fOffset.fY);
            draw.drawPath(path, rec->fPaint);
        }
    }
    return true;
}
    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);
}
Example #12
0
    AAClipBuilderBench(void* param, bool doPath, bool doAA) : INHERITED(param) {
        fDoPath = doPath;
        fDoAA = doAA;

        fName.printf("aaclip_build_%s_%s", doPath ? "path" : "rect",
                     doAA ? "AA" : "BW");

        fRegion.setRect(0, 0, 640, 480);
        fRect.set(fRegion.getBounds());
        fRect.inset(SK_Scalar1/4, SK_Scalar1/4);
        fPath.addRoundRect(fRect, SkIntToScalar(20), SkIntToScalar(20));
    }
Example #13
0
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft)
{
    SkRegion rgn;
    SkRegion clip;

    SkPath::FillType originalFillType = originalPath->getFillType();

    const SkPath* path = originalPath;
    SkPath scaledPath;
    int scale = 1;

    SkRect bounds;
    // FIXME:  This #ifdef can go away once we're firmly using the new Skia.
    // During the transition, this makes the code compatible with both versions.
#ifdef SK_USE_OLD_255_TO_256
    bounds = originalPath->getBounds();
#else
    originalPath->computeBounds(&bounds, SkPath::kFast_BoundsType);
#endif

    // We can immediately return false if the point is outside the bounding rect
    if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y())))
        return false;

    originalPath->setFillType(ft);

    // Skia has trouble with coordinates close to the max signed 16-bit values
    // If we have those, we need to scale. 
    //
    // TODO: remove this code once Skia is patched to work properly with large
    // values
    const SkScalar kMaxCoordinate = SkIntToScalar(1<<15);
    SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop);

    if (biggestCoord > kMaxCoordinate) {
        scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate));

        SkMatrix m;
        m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale)));
        originalPath->transform(m, &scaledPath);
        path = &scaledPath;
    }

    int x = static_cast<int>(floorf(point.x() / scale));
    int y = static_cast<int>(floorf(point.y() / scale));
    clip.setRect(x, y, x + 1, y + 1);

    bool contains = rgn.setPath(*path, clip);

    originalPath->setFillType(originalFillType);
    return contains;
}
    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;
    }
bool SkRasterClip::setPath(const SkPath& path, const SkRasterClip& clip,
                           bool doAA) {
    if (clip.isBW()) {
        return this->setPath(path, clip.bwRgn(), doAA);
    } else {
        SkRegion tmp;
        tmp.setRect(clip.getBounds());
        if (!this->setPath(path, clip, doAA)) {
            return false;
        }
        return this->op(clip, SkRegion::kIntersect_Op);
    }
}
SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
    SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
    SkASSERT(fPicture);
    // Clip the tile to an area that is completely inside both the SkPicture and the viewport. This
    // is mostly important for tiles on the right and bottom edges as they may go over this area and
    // the picture may have some commands that draw outside of this area and so should not actually
    // be written.
    // Uses a clipRegion so that it will be unaffected by the scale factor, which may have been set
    // by INHERITED::setupCanvas.
    SkRegion clipRegion;
    clipRegion.setRect(0, 0, this->getViewWidth(), this->getViewHeight());
    canvas->clipRegion(clipRegion);
    return canvas;
}
Example #17
0
bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::FillType ft)
{
	SkRegion rgn;
	SkRegion clip;

	SkPath::FillType originalFillType = originalPath->getFillType();

	const SkPath* path = originalPath;
	SkPath scaledPath;
	int scale = 1;

	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;

	originalPath->setFillType(ft);

	// Skia has trouble with coordinates close to the max signed 16-bit values
	// If we have those, we need to scale. 
	//
	// TODO: remove this code once Skia is patched to work properly with large
	// values
	const SkScalar kMaxCoordinate = SkIntToScalar(1<<15);
	SkScalar biggestCoord = std::max(std::max(std::max(bounds.fRight, bounds.fBottom), -bounds.fLeft), -bounds.fTop);

	if (biggestCoord > kMaxCoordinate) {
		scale = SkScalarCeil(SkScalarDiv(biggestCoord, kMaxCoordinate));

		SkMatrix m;
		m.setScale(SkScalarInvert(SkIntToScalar(scale)), SkScalarInvert(SkIntToScalar(scale)));
		originalPath->transform(m, &scaledPath);
		path = &scaledPath;
	}

	int x = static_cast<int>(floorf(point.x() / scale));
	int y = static_cast<int>(floorf(point.y() / scale));
	clip.setRect(x - 1, y - 1, x + 1, y + 1);

	bool contains = rgn.setPath(*path, clip);

	originalPath->setFillType(originalFillType);
	return contains;
}
Example #18
0
void mbe_scissoring(mbe_t *canvas, int n_areas, area_t **areas) {
    SkRegion region;
    area_t *area;
    co_aix right, bottom;
    int i;

    for(i = 0; i < n_areas; i++) {
	area = areas[i];
	right = area->x + area->w;
	bottom = area->y + area->h;
	region.setRect(area->x, area->y, right, bottom);
	canvas->canvas->clipRegion(region, SkRegion::kIntersect_Op);
    }
}
Example #19
0
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);
}
Example #20
0
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;
}
Example #21
0
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);
        }
    }
Example #23
0
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);
}
Example #24
0
 static SkRegion TestRegion() {
     SkRegion region;
     SkIRect rect = SkIRect::MakeXYWH(0, 0, 2, 1);
     region.setRect(rect);
     return region;
 }
static jboolean Region_setRect(JNIEnv* env, jobject, jlong dstHandle, jint left, jint top, jint right, jint bottom) {
    SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle);
    bool result = dst->setRect(left, top, right, bottom);
    return boolTojboolean(result);
}
Example #26
0
void SkScalerContext::getImage(const SkGlyph& origGlyph) {
    const SkGlyph*  glyph = &origGlyph;
    SkGlyph         tmpGlyph;

    if (fMaskFilter) {   // restore the prefilter bounds
        tmpGlyph.init(origGlyph.fID);

        // need the original bounds, sans our maskfilter
        SkMaskFilter* mf = fMaskFilter;
        fMaskFilter = NULL;             // temp disable
        this->getMetrics(&tmpGlyph);
        fMaskFilter = mf;               // restore

        tmpGlyph.fImage = origGlyph.fImage;

        // we need the prefilter bounds to be <= filter bounds
        SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
        SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
        glyph = &tmpGlyph;
    }

    if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
        SkPath      devPath, fillPath;
        SkMatrix    fillToDevMatrix;

        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);

        if (fRasterizer) {
            SkMask  mask;

            glyph->toMask(&mask);
            mask.fFormat = SkMask::kA8_Format;
            sk_bzero(glyph->fImage, mask.computeImageSize());

            if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
                                        fMaskFilter, &mask,
                                        SkMask::kJustRenderImage_CreateMode)) {
                return;
            }
        } else {
            SkBitmap    bm;
            SkBitmap::Config config;
            SkMatrix    matrix;
            SkRegion    clip;
            SkPaint     paint;
            SkDraw      draw;

            if (SkMask::kA8_Format == fRec.fMaskFormat) {
                config = SkBitmap::kA8_Config;
                paint.setAntiAlias(true);
            } else {
                SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat);
                config = SkBitmap::kA1_Config;
                paint.setAntiAlias(false);
            }

            clip.setRect(0, 0, glyph->fWidth, glyph->fHeight);
            matrix.setTranslate(-SkIntToScalar(glyph->fLeft),
                                -SkIntToScalar(glyph->fTop));
            bm.setConfig(config, glyph->fWidth, glyph->fHeight,
                         glyph->rowBytes());
            bm.setPixels(glyph->fImage);
            sk_bzero(glyph->fImage, bm.height() * bm.rowBytes());

            draw.fClip  = &clip;
            draw.fMatrix = &matrix;
            draw.fBitmap = &bm;
            draw.fBounder = NULL;
            draw.drawPath(devPath, paint);
        }
    } else {
        this->getGlyphContext(*glyph)->generateImage(*glyph);
    }

    if (fMaskFilter) {
        SkMask      srcM, dstM;
        SkMatrix    matrix;

        // the src glyph image shouldn't be 3D
        SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
        glyph->toMask(&srcM);
        fRec.getMatrixFrom2x2(&matrix);

        if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
            int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
            int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
            int dstRB = origGlyph.rowBytes();
            int srcRB = dstM.fRowBytes;

            const uint8_t* src = (const uint8_t*)dstM.fImage;
            uint8_t* dst = (uint8_t*)origGlyph.fImage;

            if (SkMask::k3D_Format == dstM.fFormat) {
                // we have to copy 3 times as much
                height *= 3;
            }

            // clean out our glyph, since it may be larger than dstM
            //sk_bzero(dst, height * dstRB);

            while (--height >= 0) {
                memcpy(dst, src, width);
                src += srcRB;
                dst += dstRB;
            }
            SkMask::FreeImage(dstM.fImage);
        }
    }

    // check to see if we should filter the alpha channel

    if (NULL == fMaskFilter &&
        fRec.fMaskFormat != SkMask::kBW_Format &&
        fRec.fMaskFormat != SkMask::kLCD16_Format &&
        fRec.fMaskFormat != SkMask::kLCD32_Format &&
        (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
    {
        const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable;
        if (NULL != table) {
            uint8_t* dst = (uint8_t*)origGlyph.fImage;
            unsigned rowBytes = origGlyph.rowBytes();

            for (int y = origGlyph.fHeight - 1; y >= 0; --y) {
                for (int x = origGlyph.fWidth - 1; x >= 0; --x) {
                    dst[x] = table[dst[x]];
                }
                dst += rowBytes;
            }
        }
    }
}
Example #27
0
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;
}
void GLExtras::drawRegion(const SkRegion& region, bool fill, bool drawBorder,
                          const TransformationMatrix* drawMat, Color color)
{
    if (region.isEmpty())
        return;
    if (fill) {
        SkRegion::Iterator rgnIter(region);
        while (!rgnIter.done()) {
            const SkIRect& ir = rgnIter.rect();
            SkRect r;
            r.set(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom);
            drawRing(r, color, drawMat);
            rgnIter.next();
        }
    }
    if (fill && !drawBorder)
        return;
    SkPath path;
    if (!region.getBoundaryPath(&path))
        return;
    SkPath::Iter iter(path, true);
    SkPath::Verb verb;
    SkPoint pts[4];
    SkRegion clip;
    SkIRect startRect;
    while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
        if (verb == SkPath::kLine_Verb) {
            SkRect r;
            r.set(pts, 2);
            SkIRect line;
            int borderWidth = RING_BORDER_WIDTH;
            if (!fill)
                borderWidth *= 2;
            line.fLeft = r.fLeft - borderWidth;
            line.fRight = r.fRight + borderWidth;
            line.fTop = r.fTop - borderWidth;
            line.fBottom = r.fBottom + borderWidth;
            if (clip.intersects(line)) {
                clip.op(line, SkRegion::kReverseDifference_Op);
                if (clip.isEmpty())
                    continue; // Nothing to draw, continue
                line = clip.getBounds();
                if (SkIRect::Intersects(startRect, line)) {
                    clip.op(startRect, SkRegion::kDifference_Op);
                    if (clip.isEmpty())
                        continue; // Nothing to draw, continue
                    line = clip.getBounds();
                }
            } else {
                clip.setRect(line);
            }
            r.set(line.fLeft, line.fTop, line.fRight, line.fBottom);
            drawRing(r, color, drawMat);
            if (startRect.isEmpty()) {
                startRect.set(line.fLeft, line.fTop, line.fRight, line.fBottom);
            }
        }
        if (verb == SkPath::kMove_Verb) {
            startRect.setEmpty();
        }
    }
}
bool SkRasterClip::setPath(const SkPath& path, const SkIRect& clip, bool doAA) {
    SkRegion tmp;
    tmp.setRect(clip);
    return this->setPath(path, tmp, doAA);
}
Example #30
0
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()));
}