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

Commit cd3a8245 authored by Chris Craik's avatar Chris Craik Committed by Android (Google) Code Review
Browse files

Merge "DO NOT MERGE Inspect SkShader to determine hw shader." into lmp-preview-dev

parents c1631fd8 0fa2bd69
Loading
Loading
Loading
Loading
+93 −262
Original line number Diff line number Diff line
@@ -41,10 +41,6 @@ import android.text.TextUtils;
 * An implementation of Canvas on top of OpenGL ES 2.0.
 */
class GLES20Canvas extends HardwareCanvas {
    // Must match modifiers used in the JNI layer
    private static final int MODIFIER_NONE = 0;
    private static final int MODIFIER_SHADER = 2;

    private final boolean mOpaque;
    protected long mRenderer;

@@ -650,13 +646,8 @@ class GLES20Canvas extends HardwareCanvas {
    @Override
    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
            Paint paint) {
        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
        try {
        nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
                startAngle, sweepAngle, useCenter, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawArc(long renderer, float left, float top,
@@ -672,7 +663,6 @@ class GLES20Canvas extends HardwareCanvas {
    public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
        Bitmap bitmap = patch.getBitmap();
        throwIfCannotDraw(bitmap);
        // Shaders are ignored when drawing patches
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
@@ -682,7 +672,6 @@ class GLES20Canvas extends HardwareCanvas {
    public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
        Bitmap bitmap = patch.getBitmap();
        throwIfCannotDraw(bitmap);
        // Shaders are ignored when drawing patches
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, patch.mNativeChunk,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
@@ -694,14 +683,8 @@ class GLES20Canvas extends HardwareCanvas {
    @Override
    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
        throwIfCannotDraw(bitmap);
        // Shaders are ignored when drawing bitmaps
        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
        try {
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@@ -710,15 +693,9 @@ class GLES20Canvas extends HardwareCanvas {
    @Override
    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
        throwIfCannotDraw(bitmap);
        // Shaders are ignored when drawing bitmaps
        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
        try {
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
                matrix.native_instance, nativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@@ -727,9 +704,6 @@ class GLES20Canvas extends HardwareCanvas {
    @Override
    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
        throwIfCannotDraw(bitmap);
        // Shaders are ignored when drawing bitmaps
        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
        try {
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;

        int left, top, right, bottom;
@@ -746,17 +720,11 @@ class GLES20Canvas extends HardwareCanvas {

        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    @Override
    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
        throwIfCannotDraw(bitmap);
        // Shaders are ignored when drawing bitmaps
        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
        try {
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;

        float left, top, right, bottom;
@@ -773,9 +741,6 @@ class GLES20Canvas extends HardwareCanvas {

        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawBitmap(long renderer, long bitmap, byte[] buffer,
@@ -805,7 +770,6 @@ class GLES20Canvas extends HardwareCanvas {
            throw new ArrayIndexOutOfBoundsException();
        }

        // Shaders are ignored when drawing bitmaps
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmap(mRenderer, colors, offset, stride, x, y,
                width, height, hasAlpha, nativePaint);
@@ -817,7 +781,6 @@ class GLES20Canvas extends HardwareCanvas {
    @Override
    public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
            int width, int height, boolean hasAlpha, Paint paint) {
        // Shaders are ignored when drawing bitmaps
        drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
    }

@@ -840,14 +803,9 @@ class GLES20Canvas extends HardwareCanvas {
            checkRange(colors.length, colorOffset, count);
        }

        int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
        try {
        final long nativePaint = paint == null ? 0 : paint.mNativePaint;
        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
                verts, vertOffset, colors, colorOffset, nativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawBitmapMesh(long renderer, long bitmap, byte[] buffer,
@@ -856,12 +814,7 @@ class GLES20Canvas extends HardwareCanvas {

    @Override
    public void drawCircle(float cx, float cy, float radius, Paint paint) {
        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
        try {
        nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawCircle(long renderer, float cx, float cy,
@@ -906,12 +859,7 @@ class GLES20Canvas extends HardwareCanvas {
        if ((offset | count) < 0 || offset + count > pts.length) {
            throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
        }
        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
        try {
        nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawLines(long renderer, float[] points,
@@ -924,12 +872,7 @@ class GLES20Canvas extends HardwareCanvas {

    @Override
    public void drawOval(RectF oval, Paint paint) {
        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
        try {
        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawOval(long renderer, float left, float top,
@@ -944,8 +887,6 @@ class GLES20Canvas extends HardwareCanvas {

    @Override
    public void drawPath(Path path, Paint paint) {
        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
        try {
        if (path.isSimplePath) {
            if (path.rects != null) {
                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
@@ -953,21 +894,13 @@ class GLES20Canvas extends HardwareCanvas {
        } else {
            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
        }
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawPath(long renderer, long path, long paint);
    private static native void nDrawRects(long renderer, long region, long paint);

    void drawRects(float[] rects, int count, Paint paint) {
        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
        try {
        nDrawRects(mRenderer, rects, count, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawRects(long renderer, float[] rects, int count, long paint);
@@ -1029,12 +962,7 @@ class GLES20Canvas extends HardwareCanvas {
    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
        if (count < 2) return;

        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
        try {
        nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawPoints(long renderer, float[] points,
@@ -1047,12 +975,7 @@ class GLES20Canvas extends HardwareCanvas {
            throw new IndexOutOfBoundsException();
        }

        int modifiers = setupModifiers(paint);
        try {
        nDrawPosText(mRenderer, text, index, count, pos, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawPosText(long renderer, char[] text, int index, int count,
@@ -1065,12 +988,7 @@ class GLES20Canvas extends HardwareCanvas {
            throw new ArrayIndexOutOfBoundsException();
        }

        int modifiers = setupModifiers(paint);
        try {
        nDrawPosText(mRenderer, text, 0, text.length(), pos, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawPosText(long renderer, String text, int start, int end,
@@ -1079,12 +997,7 @@ class GLES20Canvas extends HardwareCanvas {
    @Override
    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
        if (left == right || top == bottom) return;
        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
        try {
        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawRect(long renderer, float left, float top,
@@ -1108,12 +1021,7 @@ class GLES20Canvas extends HardwareCanvas {
    @Override
    public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
            Paint paint) {
        int modifiers = setupModifiers(paint, MODIFIER_SHADER);
        try {
        nDrawRoundRect(mRenderer, left, top, right, bottom, rx, ry, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawRoundRect(long renderer, float left, float top,
@@ -1125,13 +1033,8 @@ class GLES20Canvas extends HardwareCanvas {
            throw new IndexOutOfBoundsException();
        }

        int modifiers = setupModifiers(paint);
        try {
            nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint,
                paint.mNativeTypeface);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
        nDrawText(mRenderer, text, index, count, x, y,
                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    }
    
    private static native void nDrawText(long renderer, char[] text, int index, int count,
@@ -1139,15 +1042,12 @@ class GLES20Canvas extends HardwareCanvas {

    @Override
    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
        int modifiers = setupModifiers(paint);
        try {
        if (text instanceof String || text instanceof SpannedString ||
                text instanceof SpannableString) {
            nDrawText(mRenderer, text.toString(), start, end, x, y, paint.mBidiFlags,
                    paint.mNativePaint, paint.mNativeTypeface);
        } else if (text instanceof GraphicsOperations) {
                ((GraphicsOperations) text).drawText(this, start, end, x, y,
                                                         paint);
            ((GraphicsOperations) text).drawText(this, start, end, x, y, paint);
        } else {
            char[] buf = TemporaryBuffer.obtain(end - start);
            TextUtils.getChars(text, start, end, buf, 0);
@@ -1155,9 +1055,6 @@ class GLES20Canvas extends HardwareCanvas {
                    paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
            TemporaryBuffer.recycle(buf);
        }
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    @Override
@@ -1166,13 +1063,8 @@ class GLES20Canvas extends HardwareCanvas {
            throw new IndexOutOfBoundsException();
        }

        int modifiers = setupModifiers(paint);
        try {
            nDrawText(mRenderer, text, start, end, x, y, paint.mBidiFlags, paint.mNativePaint,
                paint.mNativeTypeface);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
        nDrawText(mRenderer, text, start, end, x, y,
                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    }

    private static native void nDrawText(long renderer, String text, int start, int end,
@@ -1180,13 +1072,8 @@ class GLES20Canvas extends HardwareCanvas {

    @Override
    public void drawText(String text, float x, float y, Paint paint) {
        int modifiers = setupModifiers(paint);
        try {
            nDrawText(mRenderer, text, 0, text.length(), x, y, paint.mBidiFlags,
                    paint.mNativePaint, paint.mNativeTypeface);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
        nDrawText(mRenderer, text, 0, text.length(), x, y,
                paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
    }

    @Override
@@ -1196,13 +1083,8 @@ class GLES20Canvas extends HardwareCanvas {
            throw new ArrayIndexOutOfBoundsException();
        }

        int modifiers = setupModifiers(paint);
        try {
        nDrawTextOnPath(mRenderer, text, index, count, path.mNativePath, hOffset, vOffset,
                paint.mBidiFlags, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawTextOnPath(long renderer, char[] text, int index, int count,
@@ -1212,13 +1094,8 @@ class GLES20Canvas extends HardwareCanvas {
    public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
        if (text.length() == 0) return;

        int modifiers = setupModifiers(paint);
        try {
        nDrawTextOnPath(mRenderer, text, 0, text.length(), path.mNativePath, hOffset, vOffset,
                paint.mBidiFlags, paint.mNativePaint);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawTextOnPath(long renderer, String text, int start, int end,
@@ -1234,13 +1111,8 @@ class GLES20Canvas extends HardwareCanvas {
            throw new IllegalArgumentException("Unknown direction: " + dir);
        }

        int modifiers = setupModifiers(paint);
        try {
        nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir,
                paint.mNativePaint, paint.mNativeTypeface);
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawTextRun(long renderer, char[] text, int index, int count,
@@ -1253,8 +1125,6 @@ class GLES20Canvas extends HardwareCanvas {
            throw new IndexOutOfBoundsException();
        }

        int modifiers = setupModifiers(paint);
        try {
        int flags = dir == 0 ? 0 : 1;
        if (text instanceof String || text instanceof SpannedString ||
                text instanceof SpannableString) {
@@ -1272,9 +1142,6 @@ class GLES20Canvas extends HardwareCanvas {
                    x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
            TemporaryBuffer.recycle(buf);
        }
        } finally {
            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
        }
    }

    private static native void nDrawTextRun(long renderer, String text, int start, int end,
@@ -1286,40 +1153,4 @@ class GLES20Canvas extends HardwareCanvas {
            int indexOffset, int indexCount, Paint paint) {
        // TODO: Implement
    }

    private int setupModifiers(Bitmap b, Paint paint) {
        if (b.getConfig() != Bitmap.Config.ALPHA_8) {
            return MODIFIER_NONE;
        } else {
            return setupModifiers(paint);
        }
    }

    private int setupModifiers(Paint paint) {
        int modifiers = MODIFIER_NONE;

        final Shader shader = paint.getShader();
        if (shader != null) {
            nSetupShader(mRenderer, shader.native_shader);
            modifiers |= MODIFIER_SHADER;
        }

        return modifiers;
    }

    private int setupModifiers(Paint paint, int flags) {
        int modifiers = MODIFIER_NONE;

        final Shader shader = paint.getShader();
        if (shader != null && (flags & MODIFIER_SHADER) != 0) {
            nSetupShader(mRenderer, shader.native_shader);
            modifiers |= MODIFIER_SHADER;
        }

        return modifiers;
    }

    private static native void nSetupShader(long renderer, long shader);

    private static native void nResetModifiers(long renderer, int modifiers);
}
+4 −293

File changed.

Preview size limit exceeded, changes collapsed.

+0 −24
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@
#include <DisplayListRenderer.h>
#include <LayerRenderer.h>
#include <OpenGLRenderer.h>
#include <SkiaShader.h>
#include <Stencil.h>
#include <Rect.h>
#include <RenderNode.h>
@@ -85,8 +84,6 @@ using namespace uirenderer;
    #define RENDERER_LOGD(...)
#endif

#define MODIFIER_SHADER 2

// ----------------------------------------------------------------------------

static struct {
@@ -615,24 +612,6 @@ static void android_view_GLES20Canvas_drawLines(JNIEnv* env, jobject clazz,
    env->ReleaseFloatArrayElements(points, storage, 0);
}

// ----------------------------------------------------------------------------
// Shaders and color filters
// ----------------------------------------------------------------------------

static void android_view_GLES20Canvas_resetModifiers(JNIEnv* env, jobject clazz,
        jlong rendererPtr, jint modifiers) {
    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
    if (modifiers & MODIFIER_SHADER) renderer->resetShader();
}

static void android_view_GLES20Canvas_setupShader(JNIEnv* env, jobject clazz,
        jlong rendererPtr, jlong shaderPtr) {
    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
    SkiaShader* shader = reinterpret_cast<SkiaShader*>(shaderPtr);
    renderer->setupShader(shader);
}


// ----------------------------------------------------------------------------
// Draw filters
// ----------------------------------------------------------------------------
@@ -1091,9 +1070,6 @@ static JNINativeMethod gMethods[] = {
    { "nDrawPath",          "(JJJ)V",          (void*) android_view_GLES20Canvas_drawPath },
    { "nDrawLines",         "(J[FIIJ)V",       (void*) android_view_GLES20Canvas_drawLines },

    { "nResetModifiers",    "(JI)V",           (void*) android_view_GLES20Canvas_resetModifiers },
    { "nSetupShader",       "(JJ)V",           (void*) android_view_GLES20Canvas_setupShader },

    { "nSetupPaintFilter",  "(JII)V",          (void*) android_view_GLES20Canvas_setupPaintFilter },
    { "nResetPaintFilter",  "(J)V",            (void*) android_view_GLES20Canvas_resetPaintFilter },

+0 −3
Original line number Diff line number Diff line
@@ -44,7 +44,6 @@ public class BitmapShader extends Shader {
        mTileY = tileY;
        final long b = bitmap.ni();
        native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt);
        native_shader = nativePostCreate(native_instance, b, tileX.nativeInt, tileY.nativeInt);
    }

    /**
@@ -59,6 +58,4 @@ public class BitmapShader extends Shader {

    private static native long nativeCreate(long native_bitmap, int shaderTileModeX,
            int shaderTileModeY);
    private static native long nativePostCreate(long native_shader, long native_bitmap,
            int shaderTileModeX, int shaderTileModeY);
}
+0 −14
Original line number Diff line number Diff line
@@ -55,14 +55,6 @@ public class ComposeShader extends Shader {
        mXferMode = mode;
        native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance,
                (mode != null) ? mode.native_instance : 0);
        if (mode instanceof PorterDuffXfermode) {
            PorterDuff.Mode pdMode = ((PorterDuffXfermode) mode).mode;
            native_shader = nativePostCreate2(native_instance, shaderA.native_shader,
                    shaderB.native_shader, pdMode != null ? pdMode.nativeInt : 0);
        } else {
            native_shader = nativePostCreate1(native_instance, shaderA.native_shader,
                    shaderB.native_shader, mode != null ? mode.native_instance : 0);
        }
    }

    /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
@@ -79,8 +71,6 @@ public class ComposeShader extends Shader {
        mPorterDuffMode = mode;
        native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance,
                mode.nativeInt);
        native_shader = nativePostCreate2(native_instance, shaderA.native_shader,
                shaderB.native_shader, mode.nativeInt);
    }

    /**
@@ -108,8 +98,4 @@ public class ComposeShader extends Shader {
            long native_mode);
    private static native long nativeCreate2(long native_shaderA, long native_shaderB,
            int porterDuffMode);
    private static native long nativePostCreate1(long native_shader, long native_skiaShaderA,
            long native_skiaShaderB, long native_mode);
    private static native long nativePostCreate2(long native_shader, long native_skiaShaderA,
            long native_skiaShaderB, int porterDuffMode);
}
Loading