Example #1
0
void SkScan::FillPath(const SkPath& path, const SkRegion& origClip,
                      SkBlitter* blitter) {
    if (origClip.isEmpty()) {
        return;
    }

    // Our edges are fixed-point, and don't like the bounds of the clip to
    // exceed that. Here we trim the clip just so we don't overflow later on
    const SkRegion* clipPtr = &origClip;
    SkRegion finiteClip;
    if (clip_to_limit(origClip, &finiteClip)) {
        if (finiteClip.isEmpty()) {
            return;
        }
        clipPtr = &finiteClip;
    }
    // don't reference "origClip" any more, just use clipPtr


    SkRect bounds = path.getBounds();
    bool irPreClipped = false;
    if (!SkRectPriv::MakeLargeS32().contains(bounds)) {
        if (!bounds.intersect(SkRectPriv::MakeLargeS32())) {
            bounds.setEmpty();
        }
        irPreClipped = true;
    }

    SkIRect ir = conservative_round_to_int(bounds);
    if (ir.isEmpty()) {
        if (path.isInverseFillType()) {
            blitter->blitRegion(*clipPtr);
        }
        return;
    }

    SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType(), irPreClipped);

    blitter = clipper.getBlitter();
    if (blitter) {
        // we have to keep our calls to blitter in sorted order, so we
        // must blit the above section first, then the middle, then the bottom.
        if (path.isInverseFillType()) {
            sk_blit_above(blitter, ir, *clipPtr);
        }
        SkASSERT(clipper.getClipRect() == nullptr ||
                *clipper.getClipRect() == clipPtr->getBounds());
        sk_fill_path(path, clipPtr->getBounds(), blitter, ir.fTop, ir.fBottom,
                     0, clipper.getClipRect() == nullptr);
        if (path.isInverseFillType()) {
            sk_blit_below(blitter, ir, *clipPtr);
        }
    } else {
        // what does it mean to not have a blitter if path.isInverseFillType???
    }
}
Example #2
0
static void copyToMask(const SkRegion& rgn, SkMask* mask) {
    mask->fFormat = SkMask::kA8_Format;

    if (rgn.isEmpty()) {
        mask->fBounds.setEmpty();
        mask->fRowBytes = 0;
        mask->fImage = nullptr;
        return;
    }

    mask->fBounds = rgn.getBounds();
    mask->fRowBytes = mask->fBounds.width();
    mask->fImage = SkMask::AllocImage(mask->computeImageSize());
    sk_bzero(mask->fImage, mask->computeImageSize());

    SkImageInfo info = SkImageInfo::Make(mask->fBounds.width(),
                                         mask->fBounds.height(),
                                         kAlpha_8_SkColorType,
                                         kPremul_SkAlphaType);
    SkBitmap bitmap;
    bitmap.installPixels(info, mask->fImage, mask->fRowBytes);

    // canvas expects its coordinate system to always be 0,0 in the top/left
    // so we translate the rgn to match that before drawing into the mask.
    //
    SkRegion tmpRgn(rgn);
    tmpRgn.translate(-rgn.getBounds().fLeft, -rgn.getBounds().fTop);

    SkCanvas canvas(bitmap);
    canvas.clipRegion(tmpRgn);
    canvas.drawColor(SK_ColorBLACK);
}
void SkDeferredCanvas::DeferredDevice::contentsCleared() {
    if (!fRecordingCanvas->isDrawingToLayer()) {
        fFreshFrame = true;

        // TODO: find a way to transfer the state stack and layers
        // to the new recording canvas.  For now, purging only works
        // with an empty stack.
        if (fRecordingCanvas->getSaveCount() == 0) {

            // Save state that is trashed by the purge
            SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
            SkSafeRef(drawFilter); // So that it survives the purge
            SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
            SkRegion clipRegion = fRecordingCanvas->getTotalClip();

            // beginRecording creates a new recording canvas and discards the
            // old one, hence purging deferred draw ops.
            fRecordingCanvas = fPicture.beginRecording(
                                   fImmediateDevice->width(),
                                   fImmediateDevice->height(), 0);

            // Restore pre-purge state
            if (!clipRegion.isEmpty()) {
                fRecordingCanvas->clipRegion(clipRegion,
                                             SkRegion::kReplace_Op);
            }
            if (!matrix.isIdentity()) {
                fRecordingCanvas->setMatrix(matrix);
            }
            if (drawFilter) {
                fRecordingCanvas->setDrawFilter(drawFilter)->unref();
            }
        }
    }
}
Example #4
0
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);
}
Example #5
0
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;
    }


    // copy content from old composited root to new
    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);
}
Example #6
0
void SkDeferredCanvas::DeferredDevice::purgePending()
{
    // TODO: find a way to transfer the state stack and layers
    // to the new recording canvas.  For now, purge only works
    // with an empty stack.
    if (fRecordingCanvas->getSaveCount() > 1)
        return;

    // Save state that is trashed by the purge
    SkDrawFilter* drawFilter = fRecordingCanvas->getDrawFilter();
    SkSafeRef(drawFilter); // So that it survives the purge
    SkMatrix matrix = fRecordingCanvas->getTotalMatrix();
    SkRegion clipRegion = fRecordingCanvas->getTotalClip();

    // beginRecording creates a new recording canvas and discards the old one,
    // hence purging deferred draw ops.
    fRecordingCanvas = fPicture.beginRecording(fImmediateDevice->width(), 
        fImmediateDevice->height(),
        SkPicture::kUsePathBoundsForClip_RecordingFlag);

    // Restore pre-purge state
    if (!clipRegion.isEmpty()) {
        fRecordingCanvas->clipRegion(clipRegion, SkRegion::kReplace_Op);
    }
    if (!matrix.isIdentity()) {
        fRecordingCanvas->setMatrix(matrix);
    }
    if (drawFilter) {
        fRecordingCanvas->setDrawFilter(drawFilter)->unref();
    }
}
bool SkAndroidFrameworkUtils::clipWithStencil(SkCanvas* canvas) {
    SkRegion clipRegion;
    canvas->temporary_internal_getRgnClip(&clipRegion);
    if (clipRegion.isEmpty()) {
        return false;
    }
    SkBaseDevice* device = canvas->getDevice();
    if (!device) {
        return false;
    }
    GrRenderTargetContext* rtc = device->accessRenderTargetContext();
    if (!rtc) {
        return false;
    }
    GrPaint grPaint;
    grPaint.setXPFactory(GrDisableColorXPFactory::Get());
    GrNoClip noClip;
    static constexpr GrUserStencilSettings kDrawToStencil(
        GrUserStencilSettings::StaticInit<
            0x1,
            GrUserStencilTest::kAlways,
            0x1,
            GrUserStencilOp::kReplace,
            GrUserStencilOp::kReplace,
            0x1>()
    );
    rtc->drawRegion(noClip, std::move(grPaint), GrAA::kNo, SkMatrix::I(), clipRegion,
                    GrStyle::SimpleFill(), &kDrawToStencil);
    return true;
}
Example #8
0
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();
}
Example #9
0
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 RegionLayerDrawExtra::drawGL(GLExtras* glExtras, const LayerAndroid* layer)
{
    SkRegion* region = getHighlightRegionsForLayer(layer);
    if (!region || region->isEmpty())
        return;
    const TransformationMatrix* transform = layer ? layer->drawTransform() : 0;
    glExtras->drawRegion(*region, true, false, transform, m_highlightColor);
}
void RegionLayerDrawExtra::draw(SkCanvas* canvas, LayerAndroid* layer)
{
    SkRegion* region = getHighlightRegionsForLayer(layer);
    if (!region || region->isEmpty())
        return;
    SkRegion::Iterator rgnIter(*region);
    SkPaint paint;
    paint.setColor(m_highlightColor.rgb());
    while (!rgnIter.done()) {
        const SkIRect& rect = rgnIter.rect();
        canvas->drawIRect(rect, paint);
        rgnIter.next();
    }
}
    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);
    }
Example #13
0
    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;
    }
static jboolean Region_getBounds(JNIEnv* env, jobject, jlong regionHandle, jobject rectBounds) {
    SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
    GraphicsJNI::irect_to_jrect(region->getBounds(), env, rectBounds);
    bool result = !region->isEmpty();
    return boolTojboolean(result);
}
Example #15
0
void TileGrid::markAsDirty(const SkRegion& invalRegion)
{
    ALOGV("TG %p markAsDirty, current region empty %d, new empty %d",
          this, m_dirtyRegion.isEmpty(), invalRegion.isEmpty());
    m_dirtyRegion.op(invalRegion, SkRegion::kUnion_Op);
}
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();
        }
    }
}