Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39a908c1 authored by Chris Craik's avatar Chris Craik
Browse files

Fix various draw ops that may incorrectly not scissor

bug:8965976

Also consolidates quickReject scissor-ing and scissor-less paths.
Renamed plain 'quickReject' method, as it has sideEffects beyond what
the java and skia canvases do.

Change-Id: I4bdf874d3c8f469d283eae1e71c5e7ea53d47016
parent 6db10546
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -298,7 +298,7 @@ static jint android_view_GLES20Canvas_saveLayerAlphaClip(JNIEnv* env, jobject cl

static bool android_view_GLES20Canvas_quickReject(JNIEnv* env, jobject clazz,
        OpenGLRenderer* renderer, jfloat left, jfloat top, jfloat right, jfloat bottom) {
    return renderer->quickReject(left, top, right, bottom);
    return renderer->quickRejectNoScissor(left, top, right, bottom);
}

static bool android_view_GLES20Canvas_clipRectF(JNIEnv* env, jobject clazz,
+11 −4
Original line number Diff line number Diff line
@@ -356,22 +356,26 @@ void DisplayList::outputViewProperties(const int level) {
                    level * 2, "", mTransformMatrix, MATRIX_ARGS(mTransformMatrix));
        }
    }

    bool clipToBoundsNeeded = mClipToBounds;
    if (mAlpha < 1) {
        if (mCaching) {
            ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mAlpha);
            clipToBoundsNeeded = false; // clipping done by layer
        } else if (!mHasOverlappingRendering) {
            ALOGD("%*sScaleAlpha %.2f", level * 2, "", mAlpha);
        } else {
            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
            if (mClipToBounds) {
            if (clipToBoundsNeeded) {
                flags |= SkCanvas::kClipToLayer_SaveFlag;
                clipToBoundsNeeded = false; // clipping done by save layer
            }
            ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
                    (float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
                    (int)(mAlpha * 255), flags);
        }
    }
    if (mClipToBounds && !mCaching) {
    if (clipToBoundsNeeded) {
        ALOGD("%*sClipRect %.2f, %.2f, %.2f, %.2f", level * 2, "", 0.0f, 0.0f,
                (float) mRight - mLeft, (float) mBottom - mTop);
    }
@@ -406,9 +410,11 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
            renderer.concatMatrix(mTransformMatrix);
        }
    }
    bool clipToBoundsNeeded = mClipToBounds;
    if (mAlpha < 1) {
        if (mCaching) {
            renderer.setOverrideLayerAlpha(mAlpha);
            clipToBoundsNeeded = false; // clipping done by layer
        } else if (!mHasOverlappingRendering) {
            renderer.scaleAlpha(mAlpha);
        } else {
@@ -416,15 +422,16 @@ void DisplayList::setViewProperties(OpenGLRenderer& renderer, T& handler,
            // have to pass it into this call. In fact, this information might be in the
            // location/size info that we store with the new native transform data.
            int saveFlags = SkCanvas::kHasAlphaLayer_SaveFlag;
            if (mClipToBounds) {
            if (clipToBoundsNeeded) {
                saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
                clipToBoundsNeeded = false; // clipping done by saveLayer
            }
            handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
                    mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT,
                    mClipToBounds);
        }
    }
    if (mClipToBounds && !mCaching) {
    if (clipToBoundsNeeded) {
        handler(mClipRectOp->reinit(0, 0, mRight - mLeft, mBottom - mTop, SkRegion::kIntersect_Op),
                PROPERTY_SAVECOUNT, mClipToBounds);
    }
+26 −35
Original line number Diff line number Diff line
@@ -993,6 +993,10 @@ void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
    const Rect& rect = layer->layer;
    const bool fboLayer = current->flags & Snapshot::kFlagIsFboLayer;

    bool clipRequired = false;
    quickRejectNoScissor(rect, &clipRequired); // safely ignore return, should never be rejected
    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);

    if (fboLayer) {
        endTiling();

@@ -1568,8 +1572,9 @@ const Rect& OpenGLRenderer::getClipBounds() {
    return mSnapshot->getLocalClip();
}

bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom) {
    if (mSnapshot->isIgnored()) {
bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
        bool* clipRequired) {
    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
        return true;
    }

@@ -1580,23 +1585,10 @@ bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, fl
    Rect clipRect(*mSnapshot->clipRect);
    clipRect.snapToPixelBoundaries();

    return !clipRect.intersects(r);
}

bool OpenGLRenderer::quickRejectNoScissor(float left, float top, float right, float bottom,
        Rect& transformed, Rect& clip) {
    if (mSnapshot->isIgnored()) {
        return true;
    }

    transformed.set(left, top, right, bottom);
    currentTransform().mapRect(transformed);
    transformed.snapToPixelBoundaries();

    clip.set(*mSnapshot->clipRect);
    clip.snapToPixelBoundaries();
    if (!clipRect.intersects(r)) return true;

    return !clip.intersects(transformed);
    if (clipRequired) *clipRequired = !clipRect.contains(r);
    return false;
}

bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, float bottom,
@@ -1610,23 +1602,15 @@ bool OpenGLRenderer::quickRejectPreStroke(float left, float top, float right, fl
}

bool OpenGLRenderer::quickReject(float left, float top, float right, float bottom) {
    if (mSnapshot->isIgnored() || bottom <= top || right <= left) {
    bool clipRequired = false;
    if (quickRejectNoScissor(left, top, right, bottom, &clipRequired)) {
        return true;
    }

    Rect r(left, top, right, bottom);
    currentTransform().mapRect(r);
    r.snapToPixelBoundaries();

    Rect clipRect(*mSnapshot->clipRect);
    clipRect.snapToPixelBoundaries();

    bool rejected = !clipRect.intersects(r);
    if (!isDeferred() && !rejected) {
        mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clipRect.contains(r));
    if (!isDeferred()) {
        mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
    }

    return rejected;
    return false;
}

void OpenGLRenderer::debugClip() {
@@ -2163,6 +2147,9 @@ status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int mes
        return DrawGlInfo::kStatusDone;
    }

    // TODO: use quickReject on bounds from vertices
    mCaches.enableScissor();

    float left = FLT_MAX;
    float top = FLT_MAX;
    float right = FLT_MIN;
@@ -2829,6 +2816,8 @@ status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count
        return DrawGlInfo::kStatusDone;
    }

    mCaches.enableScissor();

    float x = 0.0f;
    float y = 0.0f;
    const bool pureTranslate = currentTransform().isPureTranslate();
@@ -2984,6 +2973,9 @@ status_t OpenGLRenderer::drawTextOnPath(const char* text, int bytesCount, int co
        return DrawGlInfo::kStatusDone;
    }

    // TODO: avoid scissor by calculating maximum bounds using path bounds + font metrics
    mCaches.enableScissor();

    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
    fontRenderer.setFont(paint, mat4::identity());
    fontRenderer.setTextureFiltering(true);
@@ -3059,10 +3051,9 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
        }
    }

    Rect transformed;
    Rect clip;
    bool clipRequired = false;
    const bool rejected = quickRejectNoScissor(x, y,
            x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip);
            x + layer->layer.getWidth(), y + layer->layer.getHeight(), &clipRequired);

    if (rejected) {
        if (transform && !transform->isIdentity()) {
@@ -3073,7 +3064,7 @@ status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {

    updateLayer(layer, true);

    mCaches.setScissorEnabled(mScissorOptimizationDisabled || !clip.contains(transformed));
    mCaches.setScissorEnabled(mScissorOptimizationDisabled || clipRequired);
    mCaches.activeTexture(0);

    if (CC_LIKELY(!layer->region.isEmpty())) {
+22 −14
Original line number Diff line number Diff line
@@ -252,11 +252,31 @@ public:
    virtual void concatMatrix(SkMatrix* matrix);

    ANDROID_API const Rect& getClipBounds();
    ANDROID_API bool quickReject(float left, float top, float right, float bottom);

    /**
     * Performs a quick reject but adjust the bounds to account for stroke width if necessary
     */
    bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);

    /**
     * Returns false and sets scissor based upon bounds if drawing won't be clipped out
     */
    bool quickReject(float left, float top, float right, float bottom);
    bool quickReject(const Rect& bounds) {
        return quickReject(bounds.left, bounds.top, bounds.right, bounds.bottom);
    }
    bool quickRejectNoScissor(float left, float top, float right, float bottom);

    /**
     * Same as quickReject, without the scissor, instead returning clipRequired through pointer.
     * clipRequired will be only set if not rejected
     */
    ANDROID_API bool quickRejectNoScissor(float left, float top, float right, float bottom,
            bool* clipRequired = NULL);
    bool quickRejectNoScissor(const Rect& bounds, bool* clipRequired = NULL) {
        return quickRejectNoScissor(bounds.left, bounds.top, bounds.right, bounds.bottom,
                clipRequired);
    }

    virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
    virtual bool clipPath(SkPath* path, SkRegion::Op op);
    virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
@@ -603,18 +623,6 @@ private:
     */
    void setStencilFromClip();

    /**
     * Performs a quick reject but does not affect the scissor. Returns
     * the transformed rect to test and the current clip.
     */
    bool quickRejectNoScissor(float left, float top, float right, float bottom,
            Rect& transformed, Rect& clip);

    /**
     * Performs a quick reject but adjust the bounds to account for stroke width if necessary
     */
    bool quickRejectPreStroke(float left, float top, float right, float bottom, SkPaint* paint);

    /**
     * Given the local bounds of the layer, calculates ...
     */
+1 −1
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@
namespace android {
namespace uirenderer {

#define RECT_STRING "%4.2f %4.2f %4.2f %4.2f"
#define RECT_STRING "%7.2f %7.2f %7.2f %7.2f"
#define RECT_ARGS(r) \
    (r).left, (r).top, (r).right, (r).bottom