diff options
| author | 2024-03-27 18:07:05 +0000 | |
|---|---|---|
| committer | 2024-03-27 18:07:05 +0000 | |
| commit | 1cc982e9cce0ff5aa02964d64d5719ea4b47aefd (patch) | |
| tree | 0d56fb183f66a2a2ba3d59f93e4006b0dd113b70 | |
| parent | dad0862bfb57d0bfe3ffc7861360417bcb976efb (diff) | |
| parent | c5fa24b2b905935122064dfba7ae3537a9adcb52 (diff) | |
Merge "Import draw commands" into main
40 files changed, 4439 insertions, 59 deletions
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java b/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java index ce8ca0d781e4..2d365368a013 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CompanionOperation.java @@ -21,6 +21,11 @@ import java.util.List; * Interface for the companion operations */ public interface CompanionOperation { + /** + * Read, create and add instance to operations + * @param buffer data to read to create operation + * @param operations command is to be added + */ void read(WireBuffer buffer, List<Operation> operations); // Debugging / Documentation utility functions diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java index 0e4c7430afb5..55f2dee95a34 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java +++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java @@ -331,6 +331,7 @@ public class CoreDocument { public void initFromBuffer(RemoteComposeBuffer buffer) { mOperations = new ArrayList<Operation>(); buffer.inflateFromBuffer(mOperations); + mBuffer = buffer; } /** diff --git a/core/java/com/android/internal/widget/remotecompose/core/Operations.java b/core/java/com/android/internal/widget/remotecompose/core/Operations.java index b8bb1f0f3519..54b277a2ac58 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Operations.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Operations.java @@ -17,8 +17,29 @@ package com.android.internal.widget.remotecompose.core; import com.android.internal.widget.remotecompose.core.operations.BitmapData; import com.android.internal.widget.remotecompose.core.operations.ClickArea; +import com.android.internal.widget.remotecompose.core.operations.ClipPath; +import com.android.internal.widget.remotecompose.core.operations.ClipRect; +import com.android.internal.widget.remotecompose.core.operations.DrawArc; +import com.android.internal.widget.remotecompose.core.operations.DrawBitmap; import com.android.internal.widget.remotecompose.core.operations.DrawBitmapInt; +import com.android.internal.widget.remotecompose.core.operations.DrawCircle; +import com.android.internal.widget.remotecompose.core.operations.DrawLine; +import com.android.internal.widget.remotecompose.core.operations.DrawOval; +import com.android.internal.widget.remotecompose.core.operations.DrawPath; +import com.android.internal.widget.remotecompose.core.operations.DrawRect; +import com.android.internal.widget.remotecompose.core.operations.DrawRoundRect; +import com.android.internal.widget.remotecompose.core.operations.DrawTextOnPath; +import com.android.internal.widget.remotecompose.core.operations.DrawTextRun; +import com.android.internal.widget.remotecompose.core.operations.DrawTweenPath; import com.android.internal.widget.remotecompose.core.operations.Header; +import com.android.internal.widget.remotecompose.core.operations.MatrixRestore; +import com.android.internal.widget.remotecompose.core.operations.MatrixRotate; +import com.android.internal.widget.remotecompose.core.operations.MatrixSave; +import com.android.internal.widget.remotecompose.core.operations.MatrixScale; +import com.android.internal.widget.remotecompose.core.operations.MatrixSkew; +import com.android.internal.widget.remotecompose.core.operations.MatrixTranslate; +import com.android.internal.widget.remotecompose.core.operations.PaintData; +import com.android.internal.widget.remotecompose.core.operations.PathData; import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior; import com.android.internal.widget.remotecompose.core.operations.RootContentDescription; import com.android.internal.widget.remotecompose.core.operations.TextData; @@ -48,7 +69,30 @@ public class Operations { public static final int DATA_BITMAP = 101; public static final int DATA_TEXT = 102; +/////////////////////////////===================== + public static final int CLIP_PATH = 38; + public static final int CLIP_RECT = 39; + public static final int PAINT_VALUES = 40; + public static final int DRAW_RECT = 42; + public static final int DRAW_TEXT_RUN = 43; + public static final int DRAW_CIRCLE = 46; + public static final int DRAW_LINE = 47; + public static final int DRAW_ROUND_RECT = 51; + public static final int DRAW_ARC = 52; + public static final int DRAW_TEXT_ON_PATH = 53; + public static final int DRAW_OVAL = 56; + public static final int DATA_PATH = 123; + public static final int DRAW_PATH = 124; + public static final int DRAW_TWEEN_PATH = 125; + public static final int MATRIX_SCALE = 126; + public static final int MATRIX_TRANSLATE = 127; + public static final int MATRIX_SKEW = 128; + public static final int MATRIX_ROTATE = 129; + public static final int MATRIX_SAVE = 130; + public static final int MATRIX_RESTORE = 131; + public static final int MATRIX_SET = 132; + /////////////////////////////////////////====================== public static IntMap<CompanionOperation> map = new IntMap<>(); static { @@ -60,6 +104,29 @@ public class Operations { map.put(CLICK_AREA, ClickArea.COMPANION); map.put(ROOT_CONTENT_BEHAVIOR, RootContentBehavior.COMPANION); map.put(ROOT_CONTENT_DESCRIPTION, RootContentDescription.COMPANION); + + map.put(DRAW_ARC, DrawArc.COMPANION); + map.put(DRAW_BITMAP, DrawBitmap.COMPANION); + map.put(DRAW_CIRCLE, DrawCircle.COMPANION); + map.put(DRAW_LINE, DrawLine.COMPANION); + map.put(DRAW_OVAL, DrawOval.COMPANION); + map.put(DRAW_PATH, DrawPath.COMPANION); + map.put(DRAW_RECT, DrawRect.COMPANION); + map.put(DRAW_ROUND_RECT, DrawRoundRect.COMPANION); + map.put(DRAW_TEXT_ON_PATH, DrawTextOnPath.COMPANION); + map.put(DRAW_TEXT_RUN, DrawTextRun.COMPANION); + map.put(DRAW_TWEEN_PATH, DrawTweenPath.COMPANION); + map.put(DATA_PATH, PathData.COMPANION); + map.put(PAINT_VALUES, PaintData.COMPANION); + map.put(MATRIX_RESTORE, MatrixRestore.COMPANION); + map.put(MATRIX_ROTATE, MatrixRotate.COMPANION); + map.put(MATRIX_SAVE, MatrixSave.COMPANION); + map.put(MATRIX_SCALE, MatrixScale.COMPANION); + map.put(MATRIX_SKEW, MatrixSkew.COMPANION); + map.put(MATRIX_TRANSLATE, MatrixTranslate.COMPANION); + map.put(CLIP_PATH, ClipPath.COMPANION); + map.put(CLIP_RECT, ClipRect.COMPANION); + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java index 6999cdeadfd7..eece8ad52b60 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/PaintContext.java @@ -15,6 +15,8 @@ */ package com.android.internal.widget.remotecompose.core; +import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; + /** * Specify an abstract paint context used by RemoteCompose commands to draw */ @@ -30,11 +32,74 @@ public abstract class PaintContext { } public abstract void drawBitmap(int imageId, - int srcLeft, int srcTop, int srcRight, int srcBottom, - int dstLeft, int dstTop, int dstRight, int dstBottom, - int cdId); + int srcLeft, int srcTop, int srcRight, int srcBottom, + int dstLeft, int dstTop, int dstRight, int dstBottom, + int cdId); public abstract void scale(float scaleX, float scaleY); + public abstract void translate(float translateX, float translateY); + + public abstract void drawArc(float left, + float top, + float right, + float bottom, + float startAngle, + float sweepAngle); + + public abstract void drawBitmap(int id, float left, float top, float right, float bottom); + + public abstract void drawCircle(float centerX, float centerY, float radius); + + public abstract void drawLine(float x1, float y1, float x2, float y2); + + public abstract void drawOval(float left, float top, float right, float bottom); + + public abstract void drawPath(int id, float start, float end); + + public abstract void drawRect(float left, float top, float right, float bottom); + + public abstract void drawRoundRect(float left, + float top, + float right, + float bottom, + float radiusX, + float radiusY); + + public abstract void drawTextOnPath(int textId, int pathId, float hOffset, float vOffset); + + public abstract void drawTextRun(int textID, + int start, + int end, + int contextStart, + int contextEnd, + float x, + float y, + boolean rtl); + + public abstract void drawTweenPath(int path1Id, + int path2Id, + float tween, + float start, + float stop); + + public abstract void applyPaint(PaintBundle mPaintData); + + public abstract void mtrixScale(float scaleX, float scaleY, float centerX, float centerY); + + public abstract void matrixTranslate(float translateX, float translateY); + + public abstract void matrixSkew(float skewX, float skewY); + + public abstract void matrixRotate(float rotate, float pivotX, float pivotY); + + public abstract void matrixSave(); + + public abstract void matrixRestore(); + + public abstract void clipRect(float left, float top, float right, float bottom); + + public abstract void clipPath(int pathId, int regionOp); + } diff --git a/core/java/com/android/internal/widget/remotecompose/core/Platform.java b/core/java/com/android/internal/widget/remotecompose/core/Platform.java index abda0c0d9a0c..903dab49cd06 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/Platform.java +++ b/core/java/com/android/internal/widget/remotecompose/core/Platform.java @@ -20,5 +20,8 @@ package com.android.internal.widget.remotecompose.core; */ public interface Platform { byte[] imageToByteArray(Object image); + int getImageWidth(Object image); + int getImageHeight(Object image); + float[] pathToFloatArray(Object image); } diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java index c34730fdef04..c2e81318c09a 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeBuffer.java @@ -17,12 +17,34 @@ package com.android.internal.widget.remotecompose.core; import com.android.internal.widget.remotecompose.core.operations.BitmapData; import com.android.internal.widget.remotecompose.core.operations.ClickArea; +import com.android.internal.widget.remotecompose.core.operations.ClipPath; +import com.android.internal.widget.remotecompose.core.operations.ClipRect; +import com.android.internal.widget.remotecompose.core.operations.DrawArc; +import com.android.internal.widget.remotecompose.core.operations.DrawBitmap; import com.android.internal.widget.remotecompose.core.operations.DrawBitmapInt; +import com.android.internal.widget.remotecompose.core.operations.DrawCircle; +import com.android.internal.widget.remotecompose.core.operations.DrawLine; +import com.android.internal.widget.remotecompose.core.operations.DrawOval; +import com.android.internal.widget.remotecompose.core.operations.DrawPath; +import com.android.internal.widget.remotecompose.core.operations.DrawRect; +import com.android.internal.widget.remotecompose.core.operations.DrawRoundRect; +import com.android.internal.widget.remotecompose.core.operations.DrawTextOnPath; +import com.android.internal.widget.remotecompose.core.operations.DrawTextRun; +import com.android.internal.widget.remotecompose.core.operations.DrawTweenPath; import com.android.internal.widget.remotecompose.core.operations.Header; +import com.android.internal.widget.remotecompose.core.operations.MatrixRestore; +import com.android.internal.widget.remotecompose.core.operations.MatrixRotate; +import com.android.internal.widget.remotecompose.core.operations.MatrixSave; +import com.android.internal.widget.remotecompose.core.operations.MatrixScale; +import com.android.internal.widget.remotecompose.core.operations.MatrixSkew; +import com.android.internal.widget.remotecompose.core.operations.MatrixTranslate; +import com.android.internal.widget.remotecompose.core.operations.PaintData; +import com.android.internal.widget.remotecompose.core.operations.PathData; import com.android.internal.widget.remotecompose.core.operations.RootContentBehavior; import com.android.internal.widget.remotecompose.core.operations.RootContentDescription; import com.android.internal.widget.remotecompose.core.operations.TextData; import com.android.internal.widget.remotecompose.core.operations.Theme; +import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; import java.io.File; import java.io.FileInputStream; @@ -82,10 +104,10 @@ public class RemoteComposeBuffer { /** * Insert a header * - * @param width the width of the document in pixels - * @param height the height of the document in pixels + * @param width the width of the document in pixels + * @param height the height of the document in pixels * @param contentDescription content description of the document - * @param capabilities bitmask indicating needed capabilities (unused for now) + * @param capabilities bitmask indicating needed capabilities (unused for now) */ public void header(int width, int height, String contentDescription, long capabilities) { Header.COMPANION.apply(mBuffer, width, height, capabilities); @@ -99,8 +121,8 @@ public class RemoteComposeBuffer { /** * Insert a header * - * @param width the width of the document in pixels - * @param height the height of the document in pixels + * @param width the width of the document in pixels + * @param height the height of the document in pixels * @param contentDescription content description of the document */ public void header(int width, int height, String contentDescription) { @@ -111,7 +133,7 @@ public class RemoteComposeBuffer { * Insert a bitmap * * @param image an opaque image that we'll add to the buffer - * @param imageWidth the width of the image + * @param imageWidth the width of the image * @param imageHeight the height of the image * @param srcLeft left coordinate of the source area * @param srcTop top coordinate of the source area @@ -161,13 +183,13 @@ public class RemoteComposeBuffer { /** * Add a click area to the document * - * @param id the id of the click area, reported in the click listener callback + * @param id the id of the click area, reported in the click listener callback * @param contentDescription the content description of that click area (accessibility) - * @param left left coordinate of the area bounds - * @param top top coordinate of the area bounds - * @param right right coordinate of the area bounds - * @param bottom bottom coordinate of the area bounds - * @param metadata associated metadata, user-provided + * @param left left coordinate of the area bounds + * @param top top coordinate of the area bounds + * @param right right coordinate of the area bounds + * @param bottom bottom coordinate of the area bounds + * @param metadata associated metadata, user-provided */ public void addClickArea( int id, @@ -193,35 +215,294 @@ public class RemoteComposeBuffer { /** * Sets the way the player handles the content * - * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL) + * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL) * @param alignment set the alignment of the content (TOP|CENTER|BOTTOM|START|END) - * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE) - * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes - * the LAYOUT modes are: - * - LAYOUT_MATCH_PARENT - * - LAYOUT_WRAP_CONTENT - * or adding an horizontal mode and a vertical mode: - * - LAYOUT_HORIZONTAL_MATCH_PARENT - * - LAYOUT_HORIZONTAL_WRAP_CONTENT - * - LAYOUT_HORIZONTAL_FIXED - * - LAYOUT_VERTICAL_MATCH_PARENT - * - LAYOUT_VERTICAL_WRAP_CONTENT - * - LAYOUT_VERTICAL_FIXED - * The LAYOUT_*_FIXED modes will use the intrinsic document size + * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE) + * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes + * the LAYOUT modes are: + * - LAYOUT_MATCH_PARENT + * - LAYOUT_WRAP_CONTENT + * or adding an horizontal mode and a vertical mode: + * - LAYOUT_HORIZONTAL_MATCH_PARENT + * - LAYOUT_HORIZONTAL_WRAP_CONTENT + * - LAYOUT_HORIZONTAL_FIXED + * - LAYOUT_VERTICAL_MATCH_PARENT + * - LAYOUT_VERTICAL_WRAP_CONTENT + * - LAYOUT_VERTICAL_FIXED + * The LAYOUT_*_FIXED modes will use the intrinsic document size */ public void setRootContentBehavior(int scroll, int alignment, int sizing, int mode) { RootContentBehavior.COMPANION.apply(mBuffer, scroll, alignment, sizing, mode); } + /** + * add Drawing the specified arc, which will be scaled to fit inside the specified oval. + * <br> + * If the start angle is negative or >= 360, the start angle is treated as start angle modulo + * 360. + * <br> + * If the sweep angle is >= 360, then the oval is drawn completely. Note that this differs + * slightly from SkPath::arcTo, which treats the sweep angle modulo 360. If the sweep angle is + * negative, the sweep angle is treated as sweep angle modulo 360 + * <br> + * The arc is drawn clockwise. An angle of 0 degrees correspond to the geometric angle of 0 + * degrees (3 o'clock on a watch.) + * <br> + * + * @param left left coordinate of oval used to define the shape and size of the arc + * @param top top coordinate of oval used to define the shape and size of the arc + * @param right right coordinate of oval used to define the shape and size of the arc + * @param bottom bottom coordinate of oval used to define the shape and size of the arc + * @param startAngle Starting angle (in degrees) where the arc begins + * @param sweepAngle Sweep angle (in degrees) measured clockwise + */ + public void addDrawArc(float left, + float top, + float right, + float bottom, + float startAngle, + float sweepAngle) { + DrawArc.COMPANION.apply(mBuffer, left, top, right, bottom, startAngle, sweepAngle); + } + + /** + * @param image The bitmap to be drawn + * @param left left coordinate of rectangle that the bitmap will be to fit into + * @param top top coordinate of rectangle that the bitmap will be to fit into + * @param right right coordinate of rectangle that the bitmap will be to fit into + * @param bottom bottom coordinate of rectangle that the bitmap will be to fit into + * @param contentDescription content description of the image + */ + public void addDrawBitmap(Object image, + float left, + float top, + float right, + float bottom, + String contentDescription) { + int imageId = mRemoteComposeState.dataGetId(image); + if (imageId == -1) { + imageId = mRemoteComposeState.cache(image); + byte[] data = mPlatform.imageToByteArray(image); + int imageWidth = mPlatform.getImageWidth(image); + int imageHeight = mPlatform.getImageHeight(image); + + BitmapData.COMPANION.apply(mBuffer, imageId, imageWidth, imageHeight, data); + } + int contentDescriptionId = 0; + if (contentDescription != null) { + contentDescriptionId = addText(contentDescription); + } + DrawBitmap.COMPANION.apply( + mBuffer, imageId, left, top, right, bottom, contentDescriptionId + ); + } + + /** + * Draw the specified circle using the specified paint. If radius is <= 0, then nothing will be + * drawn. + * + * @param centerX The x-coordinate of the center of the circle to be drawn + * @param centerY The y-coordinate of the center of the circle to be drawn + * @param radius The radius of the circle to be drawn + */ + public void addDrawCircle(float centerX, float centerY, float radius) { + DrawCircle.COMPANION.apply(mBuffer, centerX, centerY, radius); + } + + /** + * Draw a line segment with the specified start and stop x,y coordinates, using the specified + * paint. + * + * @param x1 The x-coordinate of the start point of the line + * @param y1 The y-coordinate of the start point of the line + * @param x2 The x-coordinate of the end point of the line + * @param y2 The y-coordinate of the end point of the line + */ + public void addDrawLine(float x1, float y1, float x2, float y2) { + DrawLine.COMPANION.apply(mBuffer, x1, y1, x2, y2); + } + + /** + * Draw the specified oval using the specified paint. + * + * @param left left coordinate of oval + * @param top top coordinate of oval + * @param right right coordinate of oval + * @param bottom bottom coordinate of oval + */ + public void addDrawOval(float left, float top, float right, float bottom) { + DrawOval.COMPANION.apply(mBuffer, left, top, right, bottom); + } + + /** + * Draw the specified path + * <p> + * Note: path objects are not immutable + * modifying them and calling this will not change the drawing + * + * @param path The path to be drawn + */ + public void addDrawPath(Object path) { + int id = mRemoteComposeState.dataGetId(path); + if (id == -1) { // never been seen before + id = addPathData(path); + } + addDrawPath(id); + } + + + /** + * Draw the specified path + * + * @param pathId + */ + public void addDrawPath(int pathId) { + DrawPath.COMPANION.apply(mBuffer, pathId); + } + + /** + * Draw the specified Rect + * + * @param left left coordinate of rectangle to be drawn + * @param top top coordinate of rectangle to be drawn + * @param right right coordinate of rectangle to be drawn + * @param bottom bottom coordinate of rectangle to be drawn + */ + public void addDrawRect(float left, float top, float right, float bottom) { + DrawRect.COMPANION.apply(mBuffer, left, top, right, bottom); + } + + /** + * Draw the specified round-rect + * + * @param left left coordinate of rectangle to be drawn + * @param top left coordinate of rectangle to be drawn + * @param right left coordinate of rectangle to be drawn + * @param bottom left coordinate of rectangle to be drawn + * @param radiusX The x-radius of the oval used to round the corners + * @param radiusY The y-radius of the oval used to round the corners + */ + public void addDrawRoundRect(float left, float top, float right, float bottom, + float radiusX, float radiusY) { + DrawRoundRect.COMPANION.apply(mBuffer, left, top, right, bottom, radiusX, radiusY); + } + + /** + * Draw the text, with origin at (x,y) along the specified path. + * + * @param text The text to be drawn + * @param path The path the text should follow for its baseline + * @param hOffset The distance along the path to add to the text's starting position + * @param vOffset The distance above(-) or below(+) the path to position the text + */ + public void addDrawTextOnPath(String text, Object path, float hOffset, float vOffset) { + int pathId = mRemoteComposeState.dataGetId(path); + if (pathId == -1) { // never been seen before + pathId = addPathData(path); + } + int textId = addText(text); + DrawTextOnPath.COMPANION.apply(mBuffer, textId, pathId, hOffset, vOffset); + } + + /** + * Draw the text, with origin at (x,y). The origin is interpreted + * based on the Align setting in the paint. + * + * @param text The text to be drawn + * @param start The index of the first character in text to draw + * @param end (end - 1) is the index of the last character in text to draw + * @param contextStart + * @param contextEnd + * @param x The x-coordinate of the origin of the text being drawn + * @param y The y-coordinate of the baseline of the text being drawn + * @param rtl Draw RTTL + */ + public void addDrawTextRun(String text, + int start, + int end, + int contextStart, + int contextEnd, + float x, + float y, + boolean rtl) { + int textId = addText(text); + DrawTextRun.COMPANION.apply( + mBuffer, textId, start, end, + contextStart, contextEnd, x, y, rtl); + } + + /** + * draw an interpolation between two paths that have the same pattern + * <p> + * Warning paths objects are not immutable and this is not taken into consideration + * + * @param path1 The path1 to be drawn between + * @param path2 The path2 to be drawn between + * @param tween The ratio of path1 and path2 to 0 = all path 1, 1 = all path2 + * @param start The start of the subrange of paths to draw 0 = start form start 0.5 is half way + * @param stop The end of the subrange of paths to draw 1 = end at the end 0.5 is end half way + */ + public void addDrawTweenPath(Object path1, + Object path2, + float tween, + float start, + float stop) { + int path1Id = mRemoteComposeState.dataGetId(path1); + if (path1Id == -1) { // never been seen before + path1Id = addPathData(path1); + } + int path2Id = mRemoteComposeState.dataGetId(path2); + if (path2Id == -1) { // never been seen before + path2Id = addPathData(path2); + } + addDrawTweenPath(path1Id, path2Id, tween, start, stop); + } + + /** + * draw an interpolation between two paths that have the same pattern + * + * @param path1Id The path1 to be drawn between + * @param path2Id The path2 to be drawn between + * @param tween The ratio of path1 and path2 to 0 = all path 1, 1 = all path2 + * @param start The start of the subrange of paths to draw 0 = start form start .5 is 1/2 way + * @param stop The end of the subrange of paths to draw 1 = end at the end .5 is end 1/2 way + */ + public void addDrawTweenPath(int path1Id, + int path2Id, + float tween, + float start, + float stop) { + DrawTweenPath.COMPANION.apply( + mBuffer, path1Id, path2Id, + tween, start, stop); + } + + /** + * Add a path object + * + * @param path + * @return the id of the path on the wire + */ + public int addPathData(Object path) { + float[] pathData = mPlatform.pathToFloatArray(path); + int id = mRemoteComposeState.cache(path); + PathData.COMPANION.apply(mBuffer, id, pathData); + return id; + } + + public void addPaint(PaintBundle paint) { + PaintData.COMPANION.apply(mBuffer, paint); + } /////////////////////////////////////////////////////////////////////////////////////////////// public void inflateFromBuffer(ArrayList<Operation> operations) { mBuffer.setIndex(0); while (mBuffer.available()) { int opId = mBuffer.readByte(); + System.out.println(">>> " + opId); CompanionOperation operation = Operations.map.get(opId); if (operation == null) { - throw new RuntimeException("Unknown operation encountered"); + throw new RuntimeException("Unknown operation encountered " + opId); } operation.read(mBuffer, operations); } @@ -259,7 +540,7 @@ public class RemoteComposeBuffer { } public static RemoteComposeBuffer fromInputStream(InputStream inputStream, - RemoteComposeState remoteComposeState) { + RemoteComposeState remoteComposeState) { RemoteComposeBuffer buffer = new RemoteComposeBuffer(remoteComposeState); read(inputStream, buffer); return buffer; @@ -318,5 +599,86 @@ public class RemoteComposeBuffer { } } + /** + * add a Pre-concat the current matrix with the specified skew. + * + * @param skewX The amount to skew in X + * @param skewY The amount to skew in Y + */ + public void addMatrixSkew(float skewX, float skewY) { + MatrixSkew.COMPANION.apply(mBuffer, skewX, skewY); + } + + /** + * This call balances a previous call to save(), and is used to remove all + * modifications to the matrix/clip state since the last save call. + * Do not call restore() more times than save() was called. + */ + public void addMatrixRestore() { + MatrixRestore.COMPANION.apply(mBuffer); + } + + /** + * Add a saves the current matrix and clip onto a private stack. + * <p> + * Subsequent calls to translate,scale,rotate,skew,concat or clipRect, + * clipPath will all operate as usual, but when the balancing call to + * restore() is made, those calls will be forgotten, and the settings that + * existed before the save() will be reinstated. + */ + public void addMatrixSave() { + MatrixSave.COMPANION.apply(mBuffer); + } + + /** + * add a pre-concat the current matrix with the specified rotation. + * + * @param angle The amount to rotate, in degrees + * @param centerX The x-coord for the pivot point (unchanged by the rotation) + * @param centerY The y-coord for the pivot point (unchanged by the rotation) + */ + public void addMatrixRotate(float angle, float centerX, float centerY) { + MatrixRotate.COMPANION.apply(mBuffer, angle, centerX, centerY); + } + + /** + * add a Pre-concat to the current matrix with the specified translation + * + * @param dx The distance to translate in X + * @param dy The distance to translate in Y + */ + public void addMatrixTranslate(float dx, float dy) { + MatrixTranslate.COMPANION.apply(mBuffer, dx, dy); + } + + /** + * Add a pre-concat of the current matrix with the specified scale. + * + * @param scaleX The amount to scale in X + * @param scaleY The amount to scale in Y + */ + public void addMatrixScale(float scaleX, float scaleY) { + MatrixScale.COMPANION.apply(mBuffer, scaleX, scaleY, Float.NaN, Float.NaN); + } + + /** + * Add a pre-concat of the current matrix with the specified scale. + * + * @param scaleX The amount to scale in X + * @param scaleY The amount to scale in Y + * @param centerX The x-coord for the pivot point (unchanged by the scale) + * @param centerY The y-coord for the pivot point (unchanged by the scale) + */ + public void addMatrixScale(float scaleX, float scaleY, float centerX, float centerY) { + MatrixScale.COMPANION.apply(mBuffer, scaleX, scaleY, centerX, centerY); + } + + public void addClipPath(int pathId) { + ClipPath.COMPANION.apply(mBuffer, pathId); + } + + public void addClipRect(float left, float top, float right, float bottom) { + ClipRect.COMPANION.apply(mBuffer, left, top, right, bottom); + } } diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java index 1b7c6fd0f218..d16cbc5a1a16 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java @@ -37,6 +37,8 @@ public abstract class RemoteContext { public float mWidth = 0f; public float mHeight = 0f; + public abstract void loadPathData(int instanceId, float[] floatPath); + /** * The context can be used in a few different mode, allowing operations to skip being executed: * - UNSET : all operations will get executed diff --git a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java index 7c9fda5c6631..fc3202e2160d 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java +++ b/core/java/com/android/internal/widget/remotecompose/core/WireBuffer.java @@ -37,7 +37,7 @@ public class WireBuffer { this(BUFFER_SIZE); } - public void resize(int need) { + private void resize(int need) { if (mSize + need >= mMaxSize) { mMaxSize = Math.max(mMaxSize * 2, mSize + need); mBuffer = Arrays.copyOf(mBuffer, mMaxSize); @@ -120,7 +120,7 @@ public class WireBuffer { } public int readByte() { - byte value = mBuffer[mIndex]; + int value = 0xFF & mBuffer[mIndex]; mIndex++; return value; } @@ -130,6 +130,14 @@ public class WireBuffer { int v2 = (mBuffer[mIndex++] & 0xFF) << 0; return v1 + v2; } + public int peekInt() { + int tmp = mIndex; + int v1 = (mBuffer[tmp++] & 0xFF) << 24; + int v2 = (mBuffer[tmp++] & 0xFF) << 16; + int v3 = (mBuffer[tmp++] & 0xFF) << 8; + int v4 = (mBuffer[tmp++] & 0xFF) << 0; + return v1 + v2 + v3 + v4; + } public int readInt() { int v1 = (mBuffer[mIndex++] & 0xFF) << 24; diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java new file mode 100644 index 000000000000..8d4a787148ef --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipPath.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class ClipPath extends PaintOperation { + public static final Companion COMPANION = new Companion(); + int mId; + int mRegionOp; + + public ClipPath(int pathId, int regionOp) { + mId = pathId; + mRegionOp = regionOp; + } + + public static final int REPLACE = Companion.PATH_CLIP_REPLACE; + public static final int DIFFERENCE = Companion.PATH_CLIP_DIFFERENCE; + public static final int INTERSECT = Companion.PATH_CLIP_INTERSECT; + public static final int UNION = Companion.PATH_CLIP_UNION; + public static final int XOR = Companion.PATH_CLIP_XOR; + public static final int REVERSE_DIFFERENCE = Companion.PATH_CLIP_REVERSE_DIFFERENCE; + public static final int UNDEFINED = Companion.PATH_CLIP_UNDEFINED; + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mId); + } + + @Override + public String toString() { + return "ClipPath " + mId + ";"; + } + + public static class Companion implements CompanionOperation { + public static final int PATH_CLIP_REPLACE = 0; + public static final int PATH_CLIP_DIFFERENCE = 1; + public static final int PATH_CLIP_INTERSECT = 2; + public static final int PATH_CLIP_UNION = 3; + public static final int PATH_CLIP_XOR = 4; + public static final int PATH_CLIP_REVERSE_DIFFERENCE = 5; + public static final int PATH_CLIP_UNDEFINED = 6; + + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + int pack = buffer.readInt(); + int id = pack & 0xFFFFF; + int regionOp = pack >> 24; + ClipPath op = new ClipPath(id, regionOp); + operations.add(op); + } + + @Override + public String name() { + return "ClipPath"; + } + + @Override + public int id() { + return Operations.CLIP_PATH; + } + + public void apply(WireBuffer buffer, int id) { + buffer.start(Operations.CLIP_PATH); + buffer.writeInt(id); + } + } + + @Override + public void paint(PaintContext context) { + context.clipPath(mId, mRegionOp); + } +} + diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java new file mode 100644 index 000000000000..803618a91737 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/ClipRect.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class ClipRect extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mLeft; + float mTop; + float mRight; + float mBottom; + + public ClipRect( + float left, + float top, + float right, + float bottom) { + mLeft = left; + mTop = top; + mRight = right; + mBottom = bottom; + + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom); + } + + @Override + public String toString() { + return "ClipRect " + mLeft + " " + mTop + + " " + mRight + " " + mBottom + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float sLeft = buffer.readFloat(); + float srcTop = buffer.readFloat(); + float srcRight = buffer.readFloat(); + float srcBottom = buffer.readFloat(); + + ClipRect op = new ClipRect(sLeft, srcTop, srcRight, srcBottom); + operations.add(op); + } + + @Override + public String name() { + return "ClipRect"; + } + + @Override + public int id() { + return Operations.CLIP_RECT; + } + + public void apply(WireBuffer buffer, + float left, + float top, + float right, + float bottom) { + buffer.start(Operations.CLIP_RECT); + buffer.writeFloat(left); + buffer.writeFloat(top); + buffer.writeFloat(right); + buffer.writeFloat(bottom); + } + } + + @Override + public void paint(PaintContext context) { + context.clipRect(mLeft, + mTop, + mRight, + mBottom); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java new file mode 100644 index 000000000000..e829975cd39b --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawArc.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawArc extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mLeft; + float mTop; + float mRight; + float mBottom; + float mStartAngle; + float mSweepAngle; + + public DrawArc( + float left, + float top, + float right, + float bottom, + float startAngle, + float sweepAngle) { + mLeft = left; + mTop = top; + mRight = right; + mBottom = bottom; + mStartAngle = startAngle; + mSweepAngle = sweepAngle; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mLeft, + mTop, + mRight, + mBottom, + mStartAngle, + mSweepAngle); + } + + @Override + public String toString() { + return "DrawArc " + mLeft + " " + mTop + + " " + mRight + " " + mBottom + " " + + "- " + mStartAngle + " " + mSweepAngle + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float sLeft = buffer.readFloat(); + float srcTop = buffer.readFloat(); + float srcRight = buffer.readFloat(); + float srcBottom = buffer.readFloat(); + float mStartAngle = buffer.readFloat(); + float mSweepAngle = buffer.readFloat(); + DrawArc op = new DrawArc(sLeft, srcTop, srcRight, srcBottom, + mStartAngle, mSweepAngle); + operations.add(op); + } + + @Override + public String name() { + return "DrawArc"; + } + + @Override + public int id() { + return Operations.DRAW_ARC; + } + + public void apply(WireBuffer buffer, + float left, + float top, + float right, + float bottom, + float startAngle, + float sweepAngle) { + buffer.start(Operations.DRAW_ARC); + buffer.writeFloat(left); + buffer.writeFloat(top); + buffer.writeFloat(right); + buffer.writeFloat(bottom); + buffer.writeFloat(startAngle); + buffer.writeFloat(sweepAngle); + } + } + + @Override + public void paint(PaintContext context) { + context.drawArc(mLeft, + mTop, + mRight, + mBottom, + mStartAngle, + mSweepAngle); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java new file mode 100644 index 000000000000..2e971f533ed2 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmap.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawBitmap extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mLeft; + float mTop; + float mRight; + float mBottom; + int mId; + int mDescriptionId = 0; + + public DrawBitmap( + int imageId, + float left, + float top, + float right, + float bottom, + int descriptionId) { + mLeft = left; + mTop = top; + mRight = right; + mBottom = bottom; + mId = imageId; + mDescriptionId = descriptionId; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mId, mLeft, mTop, mRight, mBottom, mDescriptionId); + } + + @Override + public String toString() { + return "DrawBitmap (desc=" + mDescriptionId + ")" + mLeft + " " + mTop + + " " + mRight + " " + mBottom + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + int id = buffer.readInt(); + float sLeft = buffer.readFloat(); + float srcTop = buffer.readFloat(); + float srcRight = buffer.readFloat(); + float srcBottom = buffer.readFloat(); + int discriptionId = buffer.readInt(); + + DrawBitmap op = new DrawBitmap(id, sLeft, srcTop, srcRight, srcBottom, discriptionId); + operations.add(op); + } + + @Override + public String name() { + return "DrawOval"; + } + + @Override + public int id() { + return Operations.DRAW_BITMAP; + } + + public void apply(WireBuffer buffer, + int id, + float left, + float top, + float right, + float bottom, + int descriptionId) { + buffer.start(Operations.DRAW_BITMAP); + buffer.writeInt(id); + buffer.writeFloat(left); + buffer.writeFloat(top); + buffer.writeFloat(right); + buffer.writeFloat(bottom); + buffer.writeInt(descriptionId); + } + } + + @Override + public void paint(PaintContext context) { + context.drawBitmap(mId, mLeft, + mTop, + mRight, + mBottom); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java index 3fbdf94427d1..c2a56e7256d6 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawBitmapInt.java @@ -76,7 +76,8 @@ public class DrawBitmapInt extends PaintOperation { } public static class Companion implements CompanionOperation { - private Companion() {} + private Companion() { + } @Override public String name() { @@ -89,9 +90,9 @@ public class DrawBitmapInt extends PaintOperation { } public void apply(WireBuffer buffer, int imageId, - int srcLeft, int srcTop, int srcRight, int srcBottom, - int dstLeft, int dstTop, int dstRight, int dstBottom, - int cdId) { + int srcLeft, int srcTop, int srcRight, int srcBottom, + int dstLeft, int dstTop, int dstRight, int dstBottom, + int cdId) { buffer.start(Operations.DRAW_BITMAP_INT); buffer.writeInt(imageId); buffer.writeInt(srcLeft); diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java new file mode 100644 index 000000000000..9ce754da1b1b --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawCircle.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawCircle extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mCenterX; + float mCenterY; + float mRadius; + + public DrawCircle(float centerX, float centerY, float radius) { + mCenterX = centerX; + mCenterY = centerY; + mRadius = radius; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mCenterX, + mCenterY, + mRadius); + } + + @Override + public String toString() { + return ""; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float centerX = buffer.readFloat(); + float centerY = buffer.readFloat(); + float radius = buffer.readFloat(); + + DrawCircle op = new DrawCircle(centerX, centerY, radius); + operations.add(op); + } + + @Override + public String name() { + return ""; + } + + @Override + public int id() { + return 0; + } + + public void apply(WireBuffer buffer, float centerX, float centerY, float radius) { + buffer.start(Operations.DRAW_CIRCLE); + buffer.writeFloat(centerX); + buffer.writeFloat(centerY); + buffer.writeFloat(radius); + } + } + + @Override + public void paint(PaintContext context) { + context.drawCircle(mCenterX, + mCenterY, + mRadius); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java new file mode 100644 index 000000000000..c7a8315a2274 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawLine.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawLine extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mX1; + float mY1; + float mX2; + float mY2; + + public DrawLine( + float x1, + float y1, + float x2, + float y2) { + mX1 = x1; + mY1 = y1; + mX2 = x2; + mY2 = y2; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mX1, + mY1, + mX2, + mY2); + } + + @Override + public String toString() { + return "DrawArc " + mX1 + " " + mY1 + + " " + mX2 + " " + mY2 + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float x1 = buffer.readFloat(); + float y1 = buffer.readFloat(); + float x2 = buffer.readFloat(); + float y2 = buffer.readFloat(); + + DrawLine op = new DrawLine(x1, y1, x2, y2); + operations.add(op); + } + + @Override + public String name() { + return "DrawLine"; + } + + @Override + public int id() { + return Operations.DRAW_LINE; + } + + public void apply(WireBuffer buffer, + float x1, + float y1, + float x2, + float y2) { + buffer.start(Operations.DRAW_LINE); + buffer.writeFloat(x1); + buffer.writeFloat(y1); + buffer.writeFloat(x2); + buffer.writeFloat(y2); + } + } + + @Override + public void paint(PaintContext context) { + context.drawLine(mX1, + mY1, + mX2, + mY2); + } + +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java new file mode 100644 index 000000000000..714375335cb2 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawOval.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawOval extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mLeft; + float mTop; + float mRight; + float mBottom; + + + public DrawOval( + float left, + float top, + float right, + float bottom) { + mLeft = left; + mTop = top; + mRight = right; + mBottom = bottom; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom); + } + + @Override + public String toString() { + return "DrawOval " + mLeft + " " + mTop + + " " + mRight + " " + mBottom + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float sLeft = buffer.readFloat(); + float srcTop = buffer.readFloat(); + float srcRight = buffer.readFloat(); + float srcBottom = buffer.readFloat(); + + DrawOval op = new DrawOval(sLeft, srcTop, srcRight, srcBottom); + operations.add(op); + } + + @Override + public String name() { + return "DrawOval"; + } + + @Override + public int id() { + return Operations.DRAW_OVAL; + } + + public void apply(WireBuffer buffer, + float left, + float top, + float right, + float bottom) { + buffer.start(Operations.DRAW_OVAL); + buffer.writeFloat(left); + buffer.writeFloat(top); + buffer.writeFloat(right); + buffer.writeFloat(bottom); + } + } + + @Override + public void paint(PaintContext context) { + context.drawOval(mLeft, + mTop, + mRight, + mBottom); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java new file mode 100644 index 000000000000..7b8a9e95d9cb --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawPath.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawPath extends PaintOperation { + public static final Companion COMPANION = new Companion(); + int mId; + float mStart = 0; + float mEnd = 1; + + public DrawPath(int pathId) { + mId = pathId; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mId); + } + + @Override + public String toString() { + return "DrawPath " + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + int id = buffer.readInt(); + DrawPath op = new DrawPath(id); + operations.add(op); + } + + @Override + public String name() { + return "DrawPath"; + } + + @Override + public int id() { + return Operations.DRAW_PATH; + } + + public void apply(WireBuffer buffer, int id) { + buffer.start(Operations.DRAW_PATH); + buffer.writeInt(id); + } + } + + @Override + public void paint(PaintContext context) { + context.drawPath(mId, mStart, mEnd); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java new file mode 100644 index 000000000000..4775241faa6f --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRect.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawRect extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mLeft; + float mTop; + float mRight; + float mBottom; + + public DrawRect( + float left, + float top, + float right, + float bottom) { + mLeft = left; + mTop = top; + mRight = right; + mBottom = bottom; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom); + } + + @Override + public String toString() { + return "DrawRect " + mLeft + " " + mTop + + " " + mRight + " " + mBottom + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float sLeft = buffer.readFloat(); + float srcTop = buffer.readFloat(); + float srcRight = buffer.readFloat(); + float srcBottom = buffer.readFloat(); + + DrawRect op = new DrawRect(sLeft, srcTop, srcRight, srcBottom); + operations.add(op); + } + + @Override + public String name() { + return "DrawRect"; + } + + @Override + public int id() { + return Operations.DRAW_RECT; + } + + public void apply(WireBuffer buffer, + float left, + float top, + float right, + float bottom) { + buffer.start(Operations.DRAW_RECT); + buffer.writeFloat(left); + buffer.writeFloat(top); + buffer.writeFloat(right); + buffer.writeFloat(bottom); + } + } + + @Override + public void paint(PaintContext context) { + context.drawRect(mLeft, + mTop, + mRight, + mBottom); + } + +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java new file mode 100644 index 000000000000..8da16e768b7f --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawRoundRect.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawRoundRect extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mLeft; + float mTop; + float mRight; + float mBottom; + float mRadiusX; + float mRadiusY; + + public DrawRoundRect( + float left, + float top, + float right, + float bottom, + float radiusX, + float radiusY) { + mLeft = left; + mTop = top; + mRight = right; + mBottom = bottom; + mRadiusX = radiusX; + mRadiusY = radiusY; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mLeft, mTop, mRight, mBottom, mRadiusX, mRadiusY); + } + + @Override + public String toString() { + return "DrawRoundRect " + mLeft + " " + mTop + + " " + mRight + " " + mBottom + + " (" + mRadiusX + " " + mRadiusY + ");"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float sLeft = buffer.readFloat(); + float srcTop = buffer.readFloat(); + float srcRight = buffer.readFloat(); + float srcBottom = buffer.readFloat(); + float srcRadiusX = buffer.readFloat(); + float srcRadiusY = buffer.readFloat(); + + DrawRoundRect op = new DrawRoundRect(sLeft, srcTop, srcRight, + srcBottom, srcRadiusX, srcRadiusY); + operations.add(op); + } + + @Override + public String name() { + return "DrawOval"; + } + + @Override + public int id() { + return Operations.DRAW_ROUND_RECT; + } + + public void apply(WireBuffer buffer, + float left, + float top, + float right, + float bottom, + float radiusX, + float radiusY) { + buffer.start(Operations.DRAW_ROUND_RECT); + buffer.writeFloat(left); + buffer.writeFloat(top); + buffer.writeFloat(right); + buffer.writeFloat(bottom); + buffer.writeFloat(radiusX); + buffer.writeFloat(radiusY); + } + } + + @Override + public void paint(PaintContext context) { + context.drawRoundRect(mLeft, + mTop, + mRight, + mBottom, + mRadiusX, + mRadiusY + ); + } + +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java new file mode 100644 index 000000000000..1856e3097ec0 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextOnPath.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawTextOnPath extends PaintOperation { + public static final Companion COMPANION = new Companion(); + int mPathId; + public int mTextId; + float mVOffset; + float mHOffset; + + public DrawTextOnPath(int textId, int pathId, float hOffset, float vOffset) { + mPathId = pathId; + mTextId = textId; + mHOffset = vOffset; + mVOffset = hOffset; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mTextId, mPathId, mHOffset, mVOffset); + } + + @Override + public String toString() { + return "DrawTextOnPath " + " " + mPathId + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + int textId = buffer.readInt(); + int pathId = buffer.readInt(); + float hOffset = buffer.readFloat(); + float vOffset = buffer.readFloat(); + DrawTextOnPath op = new DrawTextOnPath(textId, pathId, hOffset, vOffset); + operations.add(op); + } + + @Override + public String name() { + return "DrawTextOnPath"; + } + + @Override + public int id() { + return Operations.DRAW_TEXT_ON_PATH; + } + + public void apply(WireBuffer buffer, int textId, int pathId, float hOffset, float vOffset) { + buffer.start(Operations.DRAW_TEXT_ON_PATH); + buffer.writeInt(textId); + buffer.writeInt(pathId); + buffer.writeFloat(hOffset); + buffer.writeFloat(vOffset); + } + } + + @Override + public void paint(PaintContext context) { + context.drawTextOnPath(mTextId, mPathId, mHOffset, mVOffset); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextRun.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextRun.java new file mode 100644 index 000000000000..a0992528d981 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTextRun.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawTextRun extends PaintOperation { + public static final Companion COMPANION = new Companion(); + int mTextID; + int mStart = 0; + int mEnd = 0; + int mContextStart = 0; + int mContextEnd = 0; + float mX = 0f; + float mY = 0f; + boolean mRtl = false; + + public DrawTextRun(int textID, + int start, + int end, + int contextStart, + int contextEnd, + float x, + float y, + boolean rtl) { + mTextID = textID; + mStart = start; + mEnd = end; + mContextStart = contextStart; + mContextEnd = contextEnd; + mX = x; + mY = y; + mRtl = rtl; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mTextID, mStart, mEnd, mContextStart, mContextEnd, mX, mY, mRtl); + + } + + @Override + public String toString() { + return ""; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + int text = buffer.readInt(); + int start = buffer.readInt(); + int end = buffer.readInt(); + int contextStart = buffer.readInt(); + int contextEnd = buffer.readInt(); + float x = buffer.readFloat(); + float y = buffer.readFloat(); + boolean rtl = buffer.readBoolean(); + DrawTextRun op = new DrawTextRun(text, start, end, contextStart, contextEnd, x, y, rtl); + + operations.add(op); + } + + @Override + public String name() { + return ""; + } + + @Override + public int id() { + return 0; + } + + public void apply(WireBuffer buffer, + int textID, + int start, + int end, + int contextStart, + int contextEnd, + float x, + float y, + boolean rtl) { + buffer.start(Operations.DRAW_TEXT_RUN); + buffer.writeInt(textID); + buffer.writeInt(start); + buffer.writeInt(end); + buffer.writeInt(contextStart); + buffer.writeInt(contextEnd); + buffer.writeFloat(x); + buffer.writeFloat(y); + buffer.writeBoolean(rtl); + } + } + + @Override + public void paint(PaintContext context) { + context.drawTextRun(mTextID, mStart, mEnd, mContextStart, mContextEnd, mX, mY, mRtl); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java new file mode 100644 index 000000000000..ef0a4ad2eff3 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/DrawTweenPath.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class DrawTweenPath extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mTween; + float mStart; + float mStop; + int mPath1Id; + int mPath2Id; + + public DrawTweenPath( + int path1Id, + int path2Id, + float tween, + float start, + float stop) { + mTween = tween; + mStart = start; + mStop = stop; + mPath1Id = path1Id; + mPath2Id = path2Id; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mPath1Id, + mPath2Id, + mTween, + mStart, + mStop); + } + + @Override + public String toString() { + return "DrawTweenPath " + mPath1Id + " " + mPath2Id + + " " + mTween + " " + mStart + " " + + "- " + mStop + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + int path1Id = buffer.readInt(); + int path2Id = buffer.readInt(); + float tween = buffer.readFloat(); + float start = buffer.readFloat(); + float stop = buffer.readFloat(); + DrawTweenPath op = new DrawTweenPath(path1Id, path2Id, + tween, start, stop); + operations.add(op); + } + + @Override + public String name() { + return "DrawTweenPath"; + } + + @Override + public int id() { + return Operations.DRAW_TWEEN_PATH; + } + + public void apply(WireBuffer buffer, + int path1Id, + int path2Id, + float tween, + float start, + float stop) { + buffer.start(Operations.DRAW_TWEEN_PATH); + buffer.writeInt(path1Id); + buffer.writeInt(path2Id); + buffer.writeFloat(tween); + buffer.writeFloat(start); + buffer.writeFloat(stop); + } + } + + @Override + public void paint(PaintContext context) { + context.drawTweenPath(mPath1Id, + mPath2Id, + mTween, + mStart, + mStop); + } + +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java index eca43c5e3281..aabed15e833d 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Header.java @@ -26,11 +26,11 @@ import java.util.List; /** * Describe some basic information for a RemoteCompose document - * + * <p> * It encodes the version of the document (following semantic versioning) as well * as the dimensions of the document in pixels. */ -public class Header implements RemoteComposeOperation { +public class Header implements RemoteComposeOperation { public static final int MAJOR_VERSION = 0; public static final int MINOR_VERSION = 1; public static final int PATCH_VERSION = 0; @@ -89,7 +89,8 @@ public class Header implements RemoteComposeOperation { } public static class Companion implements CompanionOperation { - private Companion() {} + private Companion() { + } @Override public String name() { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java new file mode 100644 index 000000000000..482e0e22bd57 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRestore.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class MatrixRestore extends PaintOperation { + public static final Companion COMPANION = new Companion(); + + public MatrixRestore() { + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer); + } + + @Override + public String toString() { + return "MatrixRestore;"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + + MatrixRestore op = new MatrixRestore(); + operations.add(op); + } + + @Override + public String name() { + return "MatrixRestore"; + } + + @Override + public int id() { + return Operations.MATRIX_RESTORE; + } + + public void apply(WireBuffer buffer) { + buffer.start(Operations.MATRIX_RESTORE); + } + } + + @Override + public void paint(PaintContext context) { + context.matrixRestore(); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java new file mode 100644 index 000000000000..d6c89e0d2c64 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixRotate.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class MatrixRotate extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mRotate, mPivotX, mPivotY; + + public MatrixRotate(float rotate, float pivotX, float pivotY) { + mRotate = rotate; + mPivotX = pivotX; + mPivotY = pivotY; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mRotate, mPivotX, mPivotY); + } + + @Override + public String toString() { + return "DrawArc " + mRotate + ", " + mPivotX + ", " + mPivotY + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float rotate = buffer.readFloat(); + float pivotX = buffer.readFloat(); + float pivotY = buffer.readFloat(); + MatrixRotate op = new MatrixRotate(rotate, pivotX, pivotY); + operations.add(op); + } + + @Override + public String name() { + return "Matrix"; + } + + @Override + public int id() { + return Operations.MATRIX_ROTATE; + } + + public void apply(WireBuffer buffer, float rotate, float pivotX, float pivotY) { + buffer.start(Operations.MATRIX_ROTATE); + buffer.writeFloat(rotate); + buffer.writeFloat(pivotX); + buffer.writeFloat(pivotY); + } + } + + @Override + public void paint(PaintContext context) { + context.matrixRotate(mRotate, mPivotX, mPivotY); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java new file mode 100644 index 000000000000..d3d5bfba8992 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSave.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class MatrixSave extends PaintOperation { + public static final Companion COMPANION = new Companion(); + + public MatrixSave() { + + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer); + } + + @Override + public String toString() { + return "MatrixSave;"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + + MatrixSave op = new MatrixSave(); + operations.add(op); + } + + @Override + public String name() { + return "Matrix"; + } + + @Override + public int id() { + return Operations.MATRIX_SAVE; + } + + public void apply(WireBuffer buffer) { + buffer.start(Operations.MATRIX_SAVE); + } + } + + @Override + public void paint(PaintContext context) { + context.matrixSave(); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java new file mode 100644 index 000000000000..28aa68dd5884 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixScale.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class MatrixScale extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mScaleX, mScaleY; + float mCenterX, mCenterY; + + public MatrixScale(float scaleX, float scaleY, float centerX, float centerY) { + mScaleX = scaleX; + mScaleY = scaleY; + mCenterX = centerX; + mCenterY = centerY; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mScaleX, mScaleY, mCenterX, mCenterY); + } + + @Override + public String toString() { + return "MatrixScale " + mScaleY + ", " + mScaleY + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float scaleX = buffer.readFloat(); + float scaleY = buffer.readFloat(); + float centerX = buffer.readFloat(); + float centerY = buffer.readFloat(); + MatrixScale op = new MatrixScale(scaleX, scaleY, centerX, centerY); + operations.add(op); + } + + @Override + public String name() { + return "Matrix"; + } + + @Override + public int id() { + return Operations.MATRIX_SCALE; + } + + public void apply(WireBuffer buffer, float scaleX, float scaleY, + float centerX, float centerY) { + buffer.start(Operations.MATRIX_SCALE); + buffer.writeFloat(scaleX); + buffer.writeFloat(scaleY); + buffer.writeFloat(centerX); + buffer.writeFloat(centerY); + + } + } + + @Override + public void paint(PaintContext context) { + context.mtrixScale(mScaleX, mScaleY, mCenterX, mCenterY); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java new file mode 100644 index 000000000000..a3888997c758 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixSkew.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class MatrixSkew extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mSkewX, mSkewY; + + public MatrixSkew(float skewX, float skewY) { + mSkewX = skewX; + mSkewY = skewY; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mSkewX, mSkewY); + } + + @Override + public String toString() { + return "DrawArc " + mSkewY + ", " + mSkewY + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float skewX = buffer.readFloat(); + float skewY = buffer.readFloat(); + MatrixSkew op = new MatrixSkew(skewX, skewY); + operations.add(op); + } + + @Override + public String name() { + return "Matrix"; + } + + @Override + public int id() { + return Operations.MATRIX_SKEW; + } + + public void apply(WireBuffer buffer, float skewX, float skewY) { + buffer.start(Operations.MATRIX_SKEW); + buffer.writeFloat(skewX); + buffer.writeFloat(skewY); + } + } + + @Override + public void paint(PaintContext context) { + context.matrixSkew(mSkewX, mSkewY); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java new file mode 100644 index 000000000000..32987521e041 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/MatrixTranslate.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class MatrixTranslate extends PaintOperation { + public static final Companion COMPANION = new Companion(); + float mTranslateX, mTranslateY; + + public MatrixTranslate(float translateX, float translateY) { + mTranslateX = translateX; + mTranslateY = translateY; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mTranslateX, mTranslateY); + } + + @Override + public String toString() { + return "DrawArc " + mTranslateY + ", " + mTranslateY + ";"; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + float translateX = buffer.readFloat(); + float translateY = buffer.readFloat(); + MatrixTranslate op = new MatrixTranslate(translateX, translateY); + operations.add(op); + } + + @Override + public String name() { + return "Matrix"; + } + + @Override + public int id() { + return Operations.MATRIX_TRANSLATE; + } + + public void apply(WireBuffer buffer, float translateX, float translateY) { + buffer.start(Operations.MATRIX_TRANSLATE); + buffer.writeFloat(translateX); + buffer.writeFloat(translateY); + } + } + + @Override + public void paint(PaintContext context) { + context.matrixTranslate(mTranslateX, mTranslateY); + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java new file mode 100644 index 000000000000..e5683ece7919 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PaintData.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.PaintOperation; +import com.android.internal.widget.remotecompose.core.WireBuffer; +import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; + +import java.util.List; + +public class PaintData extends PaintOperation { + public PaintBundle mPaintData = new PaintBundle(); + public static final Companion COMPANION = new Companion(); + public static final int MAX_STRING_SIZE = 4000; + + public PaintData() { + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mPaintData); + } + + @Override + public String toString() { + return "PaintData " + "\"" + mPaintData + "\""; + } + + public static class Companion implements CompanionOperation { + private Companion() { + } + + @Override + public String name() { + return "TextData"; + } + + @Override + public int id() { + return Operations.PAINT_VALUES; + } + + public void apply(WireBuffer buffer, PaintBundle paintBundle) { + buffer.start(Operations.PAINT_VALUES); + paintBundle.writeBundle(buffer); + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + PaintData data = new PaintData(); + data.mPaintData.readBundle(buffer); + operations.add(data); + } + } + + @Override + public String deepToString(String indent) { + return indent + toString(); + } + + @Override + public void paint(PaintContext context) { + context.applyPaint(mPaintData); + } + +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java new file mode 100644 index 000000000000..2646b27b1f51 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/PathData.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +import com.android.internal.widget.remotecompose.core.CompanionOperation; +import com.android.internal.widget.remotecompose.core.Operation; +import com.android.internal.widget.remotecompose.core.Operations; +import com.android.internal.widget.remotecompose.core.PaintContext; +import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.List; + +public class PathData implements Operation { + public static final Companion COMPANION = new Companion(); + int mInstanceId; + float[] mRef; + float[] mFloatPath; + float[] mRetFloats; + + PathData(int instanceId, float[] floatPath) { + mInstanceId = instanceId; + mFloatPath = floatPath; + } + + @Override + public void write(WireBuffer buffer) { + COMPANION.apply(buffer, mInstanceId, mFloatPath); + } + + @Override + public String deepToString(String indent) { + return pathString(mFloatPath); + } + + public float[] getFloatPath(PaintContext context) { + float[] ret = mRetFloats; // Assume retFloats is declared elsewhere + if (ret == null) { + return mFloatPath; // Assume floatPath is declared elsewhere + } + float[] localRef = mRef; // Assume ref is of type Float[] + if (localRef == null) { + for (int i = 0; i < mFloatPath.length; i++) { + ret[i] = mFloatPath[i]; + } + } else { + for (int i = 0; i < mFloatPath.length; i++) { + float lr = localRef[i]; + if (Float.isNaN(lr)) { + ret[i] = Utils.getActualValue(lr); + } else { + ret[i] = mFloatPath[i]; + } + } + } + return ret; + } + + public static final int MOVE = 10; + public static final int LINE = 11; + public static final int QUADRATIC = 12; + public static final int CONIC = 13; + public static final int CUBIC = 14; + public static final int CLOSE = 15; + public static final int DONE = 16; + public static final float MOVE_NAN = Utils.asNan(MOVE); + public static final float LINE_NAN = Utils.asNan(LINE); + public static final float QUADRATIC_NAN = Utils.asNan(QUADRATIC); + public static final float CONIC_NAN = Utils.asNan(CONIC); + public static final float CUBIC_NAN = Utils.asNan(CUBIC); + public static final float CLOSE_NAN = Utils.asNan(CLOSE); + public static final float DONE_NAN = Utils.asNan(DONE); + + public static class Companion implements CompanionOperation { + + private Companion() { + } + + @Override + public String name() { + return "BitmapData"; + } + + @Override + public int id() { + return Operations.DATA_PATH; + } + + public void apply(WireBuffer buffer, int id, float[] data) { + buffer.start(Operations.DATA_PATH); + buffer.writeInt(id); + buffer.writeInt(data.length); + for (int i = 0; i < data.length; i++) { + buffer.writeFloat(data[i]); + } + } + + @Override + public void read(WireBuffer buffer, List<Operation> operations) { + int imageId = buffer.readInt(); + int len = buffer.readInt(); + float[] data = new float[len]; + for (int i = 0; i < data.length; i++) { + data[i] = buffer.readFloat(); + } + operations.add(new PathData(imageId, data)); + } + } + + public static String pathString(float[] path) { + if (path == null) { + return "null"; + } + StringBuilder str = new StringBuilder(); + for (int i = 0; i < path.length; i++) { + if (i != 0) { + str.append(" "); + } + if (Float.isNaN(path[i])) { + int id = Utils.idFromNan(path[i]); // Assume idFromNan is defined elsewhere + if (id <= DONE) { // Assume DONE is a constant + switch (id) { + case MOVE: + str.append("M"); + break; + case LINE: + str.append("L"); + break; + case QUADRATIC: + str.append("Q"); + break; + case CONIC: + str.append("R"); + break; + case CUBIC: + str.append("C"); + break; + case CLOSE: + str.append("Z"); + break; + case DONE: + str.append("."); + break; + default: + str.append("X"); + break; + } + } else { + str.append("(" + id + ")"); + } + } else { + str.append(path[i]); + } + } + return str.toString(); + } + + @Override + public void apply(RemoteContext context) { + context.loadPathData(mInstanceId, mFloatPath); + } + +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java index ad4caea7aef8..6d924eb70c50 100644 --- a/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/RootContentBehavior.java @@ -28,7 +28,7 @@ import java.util.List; /** * Describe some basic information for a RemoteCompose document - * + * <p> * It encodes the version of the document (following semantic versioning) as well * as the dimensions of the document in pixels. */ @@ -100,21 +100,21 @@ public class RootContentBehavior implements RemoteComposeOperation { /** * Sets the way the player handles the content * - * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL) + * @param scroll set the horizontal behavior (NONE|SCROLL_HORIZONTAL|SCROLL_VERTICAL) * @param alignment set the alignment of the content (TOP|CENTER|BOTTOM|START|END) - * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE) - * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes - * the LAYOUT modes are: - * - LAYOUT_MATCH_PARENT - * - LAYOUT_WRAP_CONTENT - * or adding an horizontal mode and a vertical mode: - * - LAYOUT_HORIZONTAL_MATCH_PARENT - * - LAYOUT_HORIZONTAL_WRAP_CONTENT - * - LAYOUT_HORIZONTAL_FIXED - * - LAYOUT_VERTICAL_MATCH_PARENT - * - LAYOUT_VERTICAL_WRAP_CONTENT - * - LAYOUT_VERTICAL_FIXED - * The LAYOUT_*_FIXED modes will use the intrinsic document size + * @param sizing set the type of sizing for the content (NONE|SIZING_LAYOUT|SIZING_SCALE) + * @param mode set the mode of sizing, either LAYOUT modes or SCALE modes + * the LAYOUT modes are: + * - LAYOUT_MATCH_PARENT + * - LAYOUT_WRAP_CONTENT + * or adding an horizontal mode and a vertical mode: + * - LAYOUT_HORIZONTAL_MATCH_PARENT + * - LAYOUT_HORIZONTAL_WRAP_CONTENT + * - LAYOUT_HORIZONTAL_FIXED + * - LAYOUT_VERTICAL_MATCH_PARENT + * - LAYOUT_VERTICAL_WRAP_CONTENT + * - LAYOUT_VERTICAL_FIXED + * The LAYOUT_*_FIXED modes will use the intrinsic document size */ public RootContentBehavior(int scroll, int alignment, int sizing, int mode) { switch (scroll) { @@ -149,10 +149,12 @@ public class RootContentBehavior implements RemoteComposeOperation { switch (sizing) { case SIZING_LAYOUT: { Log.e(TAG, "sizing_layout is not yet supported"); - } break; + } + break; case SIZING_SCALE: { mSizing = sizing; - } break; + } + break; default: { Log.e(TAG, "incorrect sizing value " + sizing); } @@ -200,7 +202,8 @@ public class RootContentBehavior implements RemoteComposeOperation { } public static class Companion implements CompanionOperation { - private Companion() {} + private Companion() { + } @Override public String name() { diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java new file mode 100644 index 000000000000..00e2f2058e89 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/Utils.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations; + +public class Utils { + public static float asNan(int v) { + return Float.intBitsToFloat(v | -0x800000); + } + + public static int idFromNan(float value) { + int b = Float.floatToRawIntBits(value); + return b & 0xFFFFF; + } + + public static float getActualValue(float lr) { + return 0; + } + + String getFloatString(float value) { + if (Float.isNaN(value)) { + int id = idFromNan(value); + if (id > 0) { + return "NaN(" + id + ")"; + } + } + return "" + value; + } +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java new file mode 100644 index 000000000000..8abb0bfff338 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintBundle.java @@ -0,0 +1,829 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.paint; + +import com.android.internal.widget.remotecompose.core.WireBuffer; + +import java.util.Arrays; + +public class PaintBundle { + int[] mArray = new int[200]; + int mPos = 0; + + public void applyPaintChange(PaintChanges p) { + int i = 0; + int mask = 0; + while (i < mPos) { + int cmd = mArray[i++]; + mask = mask | (1 << (cmd - 1)); + switch (cmd & 0xFFFF) { + case TEXT_SIZE: { + p.setTextSize(Float.intBitsToFloat(mArray[i++])); + break; + } + case TYPEFACE: + int style = (cmd >> 16); + int weight = style & 0x3ff; + boolean italic = (style >> 10) > 0; + int font_type = mArray[i++]; + + p.setTypeFace(font_type, weight, italic); + break; + case COLOR: { + p.setColor(mArray[i++]); + break; + } + case STROKE_WIDTH: { + p.setStrokeWidth(Float.intBitsToFloat(mArray[i++])); + break; + } + case STROKE_MITER: { + p.setStrokeMiter(Float.intBitsToFloat(mArray[i++])); + break; + } + case STROKE_CAP: { + p.setStrokeCap(cmd >> 16); + break; + } + case STYLE: { + p.setStyle(cmd >> 16); + break; + } + case SHADER: { + break; + } + case STROKE_JOIN: { + p.setStrokeJoin(cmd >> 16); + break; + } + case IMAGE_FILTER_QUALITY: { + p.setImageFilterQuality(cmd >> 16); + break; + } + case BLEND_MODE: { + p.setBlendMode(cmd >> 16); + break; + } + case FILTER_BITMAP: { + p.setFilterBitmap(!((cmd >> 16) == 0)); + break; + } + + case GRADIENT: { + i = callSetGradient(cmd, mArray, i, p); + break; + } + case COLOR_FILTER: { + p.setColorFilter(mArray[i++], cmd >> 16); + break; + } + case ALPHA: { + p.setAlpha(Float.intBitsToFloat(mArray[i++])); + break; + } + } + } + + mask = (~mask) & PaintChanges.VALID_BITS; + + p.clear(mask); + } + + private String toName(int id) { + switch (id) { + case TEXT_SIZE: + return "TEXT_SIZE"; + + case COLOR: + return "COLOR"; + case STROKE_WIDTH: + return "STROKE_WIDTH"; + case STROKE_MITER: + return "STROKE_MITER"; + case TYPEFACE: + return "TYPEFACE"; + case STROKE_CAP: + return "CAP"; + case STYLE: + return "STYLE"; + case SHADER: + return "SHADER"; + case IMAGE_FILTER_QUALITY: + return "IMAGE_FILTER_QUALITY"; + case BLEND_MODE: + return "BLEND_MODE"; + case FILTER_BITMAP: + return "FILTER_BITMAP"; + case GRADIENT: + return "GRADIENT_LINEAR"; + case ALPHA: + return "ALPHA"; + case COLOR_FILTER: + return "COLOR_FILTER"; + + } + return "????" + id + "????"; + } + + private static String colorInt(int color) { + String str = "000000000000" + Integer.toHexString(color); + return "0x" + str.substring(str.length() - 8); + } + + private static String colorInt(int[] color) { + String str = "["; + for (int i = 0; i < color.length; i++) { + if (i > 0) { + str += ", "; + } + str += colorInt(color[i]); + } + return str + "]"; + } + + @Override + public String toString() { + StringBuilder ret = new StringBuilder("\n"); + int i = 0; + while (i < mPos) { + int cmd = mArray[i++]; + int type = cmd & 0xFFFF; + switch (type) { + + case TEXT_SIZE: { + ret.append(" TextSize(" + Float.intBitsToFloat(mArray[i++])); + } + + break; + case TYPEFACE: { + int style = (cmd >> 16); + int weight = style & 0x3ff; + boolean italic = (style >> 10) > 0; + int font_type = mArray[i++]; + ret.append(" TypeFace(" + (font_type + ", " + + weight + ", " + italic)); + } + break; + case COLOR: { + ret.append(" Color(" + colorInt(mArray[i++])); + } + break; + case STROKE_WIDTH: { + ret.append(" StrokeWidth(" + + (Float.intBitsToFloat(mArray[i++]))); + } + break; + case STROKE_MITER: { + ret.append(" StrokeMiter(" + + (Float.intBitsToFloat(mArray[i++]))); + } + break; + case STROKE_CAP: { + ret.append(" StrokeCap(" + + (cmd >> 16)); + } + break; + case STYLE: { + ret.append(" Style(" + (cmd >> 16)); + } + break; + case COLOR_FILTER: { + ret.append(" ColorFilter(color=" + + colorInt(mArray[i++]) + + ", mode=" + blendModeString(cmd >> 16)); + } + break; + case SHADER: { + } + break; + case ALPHA: { + ret.append(" Alpha(" + + (Float.intBitsToFloat(mArray[i++]))); + } + break; + case IMAGE_FILTER_QUALITY: { + ret.append(" ImageFilterQuality(" + (cmd >> 16)); + } + break; + case BLEND_MODE: { + ret.append(" BlendMode(" + blendModeString(cmd >> 16)); + } + break; + case FILTER_BITMAP: { + ret.append(" FilterBitmap(" + + (!((cmd >> 16) == 0))); + } + break; + case STROKE_JOIN: { + ret.append(" StrokeJoin(" + (cmd >> 16)); + } + break; + case ANTI_ALIAS: { + ret.append(" AntiAlias(" + (cmd >> 16)); + } + break; + case GRADIENT: { + i = callPrintGradient(cmd, mArray, i, ret); + } + } + ret.append("),\n"); + } + return ret.toString(); + } + + + int callPrintGradient(int cmd, int[] array, int i, StringBuilder p) { + int ret = i; + int type = (cmd >> 16); + switch (type) { + + case 0: { + p.append(" LinearGradient(\n"); + int len = array[ret++]; + int[] colors = null; + if (len > 0) { + colors = new int[len]; + for (int j = 0; j < colors.length; j++) { + colors[j] = array[ret++]; + + } + } + len = array[ret++]; + float[] stops = null; + if (len > 0) { + stops = new float[len]; + for (int j = 0; j < stops.length; j++) { + stops[j] = Float.intBitsToFloat(array[ret++]); + } + } + + p.append(" colors = " + colorInt(colors) + ",\n"); + p.append(" stops = " + Arrays.toString(stops) + ",\n"); + p.append(" start = "); + p.append("[" + Float.intBitsToFloat(array[ret++])); + p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n"); + p.append(" end = "); + p.append("[" + Float.intBitsToFloat(array[ret++])); + p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n"); + int tileMode = array[ret++]; + p.append(" tileMode = " + tileMode + "\n "); + } + + break; + case 1: { + p.append(" RadialGradient(\n"); + int len = array[ret++]; + int[] colors = null; + if (len > 0) { + colors = new int[len]; + for (int j = 0; j < colors.length; j++) { + colors[j] = array[ret++]; + + } + } + len = array[ret++]; + float[] stops = null; + if (len > 0) { + stops = new float[len]; + for (int j = 0; j < stops.length; j++) { + stops[j] = Float.intBitsToFloat(array[ret++]); + } + } + + p.append(" colors = " + colorInt(colors) + ",\n"); + p.append(" stops = " + Arrays.toString(stops) + ",\n"); + p.append(" center = "); + p.append("[" + Float.intBitsToFloat(array[ret++])); + p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n"); + p.append(" radius ="); + p.append(" " + Float.intBitsToFloat(array[ret++]) + ",\n"); + int tileMode = array[ret++]; + p.append(" tileMode = " + tileMode + "\n "); + } + + break; + case 2: { + p.append(" SweepGradient(\n"); + int len = array[ret++]; + int[] colors = null; + if (len > 0) { + colors = new int[len]; + for (int j = 0; j < colors.length; j++) { + colors[j] = array[ret++]; + + } + } + len = array[ret++]; + float[] stops = null; + if (len > 0) { + stops = new float[len]; + for (int j = 0; j < stops.length; j++) { + stops[j] = Float.intBitsToFloat(array[ret++]); + } + } + + p.append(" colors = " + colorInt(colors) + ",\n"); + p.append(" stops = " + Arrays.toString(stops) + ",\n"); + p.append(" center = "); + p.append("[" + Float.intBitsToFloat(array[ret++])); + p.append(", " + Float.intBitsToFloat(array[ret++]) + "],\n "); + + } + break; + default: { + p.append("GRADIENT_??????!!!!"); + } + } + + return ret; + } + + int callSetGradient(int cmd, int[] array, int i, PaintChanges p) { + int ret = i; + int gradientType = (cmd >> 16); + + int len = array[ret++]; + int[] colors = null; + if (len > 0) { + colors = new int[len]; + for (int j = 0; j < colors.length; j++) { + colors[j] = array[ret++]; + } + } + len = array[ret++]; + float[] stops = null; + if (len > 0) { + stops = new float[len]; + for (int j = 0; j < colors.length; j++) { + stops[j] = Float.intBitsToFloat(array[ret++]); + } + } + + if (colors == null) { + return ret; + } + + + switch (gradientType) { + + case LINEAR_GRADIENT: { + float startX = Float.intBitsToFloat(array[ret++]); + float startY = Float.intBitsToFloat(array[ret++]); + float endX = Float.intBitsToFloat(array[ret++]); + float endY = Float.intBitsToFloat(array[ret++]); + int tileMode = array[ret++]; + p.setLinearGradient(colors, stops, startX, + startY, endX, endY, tileMode); + } + + break; + case RADIAL_GRADIENT: { + float centerX = Float.intBitsToFloat(array[ret++]); + float centerY = Float.intBitsToFloat(array[ret++]); + float radius = Float.intBitsToFloat(array[ret++]); + int tileMode = array[ret++]; + p.setRadialGradient(colors, stops, centerX, centerY, + radius, tileMode); + } + break; + case SWEEP_GRADIENT: { + float centerX = Float.intBitsToFloat(array[ret++]); + float centerY = Float.intBitsToFloat(array[ret++]); + p.setSweepGradient(colors, stops, centerX, centerY); + } + } + + return ret; + } + + public void writeBundle(WireBuffer buffer) { + buffer.writeInt(mPos); + for (int index = 0; index < mPos; index++) { + buffer.writeInt(mArray[index]); + } + } + + public void readBundle(WireBuffer buffer) { + int len = buffer.readInt(); + if (len <= 0 || len > 1024) { + throw new RuntimeException("buffer corrupt paint len = " + len); + } + mArray = new int[len]; + for (int i = 0; i < mArray.length; i++) { + mArray[i] = buffer.readInt(); + } + mPos = len; + } + + public static final int TEXT_SIZE = 1; // float + + public static final int COLOR = 4; // int + public static final int STROKE_WIDTH = 5; // float + public static final int STROKE_MITER = 6; + public static final int STROKE_CAP = 7; // int + public static final int STYLE = 8; // int + public static final int SHADER = 9; // int + public static final int IMAGE_FILTER_QUALITY = 10; // int + public static final int GRADIENT = 11; + public static final int ALPHA = 12; + public static final int COLOR_FILTER = 13; + public static final int ANTI_ALIAS = 14; + public static final int STROKE_JOIN = 15; + public static final int TYPEFACE = 16; + public static final int FILTER_BITMAP = 17; + public static final int BLEND_MODE = 18; + + + public static final int BLEND_MODE_CLEAR = 0; + public static final int BLEND_MODE_SRC = 1; + public static final int BLEND_MODE_DST = 2; + public static final int BLEND_MODE_SRC_OVER = 3; + public static final int BLEND_MODE_DST_OVER = 4; + public static final int BLEND_MODE_SRC_IN = 5; + public static final int BLEND_MODE_DST_IN = 6; + public static final int BLEND_MODE_SRC_OUT = 7; + public static final int BLEND_MODE_DST_OUT = 8; + public static final int BLEND_MODE_SRC_ATOP = 9; + public static final int BLEND_MODE_DST_ATOP = 10; + public static final int BLEND_MODE_XOR = 11; + public static final int BLEND_MODE_PLUS = 12; + public static final int BLEND_MODE_MODULATE = 13; + public static final int BLEND_MODE_SCREEN = 14; + public static final int BLEND_MODE_OVERLAY = 15; + public static final int BLEND_MODE_DARKEN = 16; + public static final int BLEND_MODE_LIGHTEN = 17; + public static final int BLEND_MODE_COLOR_DODGE = 18; + public static final int BLEND_MODE_COLOR_BURN = 19; + public static final int BLEND_MODE_HARD_LIGHT = 20; + public static final int BLEND_MODE_SOFT_LIGHT = 21; + public static final int BLEND_MODE_DIFFERENCE = 22; + public static final int BLEND_MODE_EXCLUSION = 23; + public static final int BLEND_MODE_MULTIPLY = 24; + public static final int BLEND_MODE_HUE = 25; + public static final int BLEND_MODE_SATURATION = 26; + public static final int BLEND_MODE_COLOR = 27; + public static final int BLEND_MODE_LUMINOSITY = 28; + public static final int BLEND_MODE_NULL = 29; + public static final int PORTER_MODE_ADD = 30; + + public static final int FONT_NORMAL = 0; + public static final int FONT_BOLD = 1; + public static final int FONT_ITALIC = 2; + public static final int FONT_BOLD_ITALIC = 3; + + public static final int FONT_TYPE_DEFAULT = 0; + public static final int FONT_TYPE_SANS_SERIF = 1; + public static final int FONT_TYPE_SERIF = 2; + public static final int FONT_TYPE_MONOSPACE = 3; + + public static final int STYLE_FILL = 0; + public static final int STYLE_STROKE = 1; + public static final int STYLE_FILL_AND_STROKE = 2; + public static final int LINEAR_GRADIENT = 0; + public static final int RADIAL_GRADIENT = 1; + public static final int SWEEP_GRADIENT = 2; + + /** + * sets a shader that draws a linear gradient along a line. + * + * @param startX The x-coordinate for the start of the gradient line + * @param startY The y-coordinate for the start of the gradient line + * @param endX The x-coordinate for the end of the gradient line + * @param endY The y-coordinate for the end of the gradient line + * @param colors The sRGB colors to be distributed along the gradient line + * @param stops May be null. The relative positions [0..1] of + * each corresponding color in the colors array. If this is null, + * the colors are distributed evenly along the gradient line. + * @param tileMode The Shader tiling mode + */ + public void setLinearGradient(int[] colors, + float[] stops, + float startX, + float startY, + float endX, + float endY, + int tileMode) { + int startPos = mPos; + int len; + mArray[mPos++] = GRADIENT | (LINEAR_GRADIENT << 16); + mArray[mPos++] = len = (colors == null) ? 0 : colors.length; + for (int i = 0; i < len; i++) { + mArray[mPos++] = colors[i]; + } + + mArray[mPos++] = len = (stops == null) ? 0 : stops.length; + for (int i = 0; i < len; i++) { + mArray[mPos++] = Float.floatToRawIntBits(stops[i]); + } + mArray[mPos++] = Float.floatToRawIntBits(startX); + mArray[mPos++] = Float.floatToRawIntBits(startY); + mArray[mPos++] = Float.floatToRawIntBits(endX); + mArray[mPos++] = Float.floatToRawIntBits(endY); + mArray[mPos++] = tileMode; + } + + /** + * Set a shader that draws a sweep gradient around a center point. + * + * @param centerX The x-coordinate of the center + * @param centerY The y-coordinate of the center + * @param colors The sRGB colors to be distributed around the center. + * There must be at least 2 colors in the array. + * @param stops May be NULL. The relative position of + * each corresponding color in the colors array, beginning + * with 0 and ending with 1.0. If the values are not + * monotonic, the drawing may produce unexpected results. + * If positions is NULL, then the colors are automatically + * spaced evenly. + */ + public void setSweepGradient(int[] colors, float[] stops, float centerX, float centerY) { + int startPos = mPos; + int len; + mArray[mPos++] = GRADIENT | (SWEEP_GRADIENT << 16); + mArray[mPos++] = len = (colors == null) ? 0 : colors.length; + for (int i = 0; i < len; i++) { + mArray[mPos++] = colors[i]; + } + + mArray[mPos++] = len = (stops == null) ? 0 : stops.length; + for (int i = 0; i < len; i++) { + mArray[mPos++] = Float.floatToRawIntBits(stops[i]); + } + mArray[mPos++] = Float.floatToRawIntBits(centerX); + mArray[mPos++] = Float.floatToRawIntBits(centerY); + } + + /** + * Sets a shader that draws a radial gradient given the center and radius. + * + * @param centerX The x-coordinate of the center of the radius + * @param centerY The y-coordinate of the center of the radius + * @param radius Must be positive. The radius of the gradient. + * @param colors The sRGB colors distributed between the center and edge + * @param stops May be <code>null</code>. + * Valid values are between <code>0.0f</code> and + * <code>1.0f</code>. The relative position of each + * corresponding color in + * the colors array. If <code>null</code>, colors are + * distributed evenly + * between the center and edge of the circle. + * @param tileMode The Shader tiling mode + */ + public void setRadialGradient(int[] colors, + float[] stops, + float centerX, + float centerY, + float radius, + int tileMode) { + int startPos = mPos; + int len; + mArray[mPos++] = GRADIENT | (RADIAL_GRADIENT << 16); + mArray[mPos++] = len = (colors == null) ? 0 : colors.length; + for (int i = 0; i < len; i++) { + mArray[mPos++] = colors[i]; + } + mArray[mPos++] = len = (stops == null) ? 0 : stops.length; + + for (int i = 0; i < len; i++) { + mArray[mPos++] = Float.floatToRawIntBits(stops[i]); + } + mArray[mPos++] = Float.floatToRawIntBits(centerX); + mArray[mPos++] = Float.floatToRawIntBits(centerY); + mArray[mPos++] = Float.floatToRawIntBits(radius); + mArray[mPos++] = tileMode; + + } + + /** + * Create a color filter that uses the specified color and Porter-Duff mode. + * + * @param color The ARGB source color used with the Porter-Duff mode + * @param mode The porter-duff mode that is applied + */ + public void setColorFilter(int color, int mode) { + mArray[mPos] = COLOR_FILTER | (mode << 16); + mPos++; + mArray[mPos++] = color; + } + + /** + * Set the paint's text size. This value must be > 0 + * + * @param size set the paint's text size in pixel units. + */ + public void setTextSize(float size) { + int p = mPos; + mArray[mPos] = TEXT_SIZE; + mPos++; + mArray[mPos] = Float.floatToRawIntBits(size); + mPos++; + } + + /** + * @param fontType 0 = default 1 = sans serif 2 = serif 3 = monospace + * @param weight 100-1000 + * @param italic tur + */ + public void setTextStyle(int fontType, int weight, boolean italic) { + int style = (weight & 0x3FF) | (italic ? 2048 : 0); // pack the weight and italic + mArray[mPos++] = TYPEFACE | (style << 16); + mArray[mPos++] = fontType; + } + + /** + * Set the width for stroking. + * Pass 0 to stroke in hairline mode. + * Hairlines always draws a single pixel independent of the canvas's matrix. + * + * @param width set the paint's stroke width, used whenever the paint's + * style is Stroke or StrokeAndFill. + */ + public void setStrokeWidth(float width) { + mArray[mPos] = STROKE_WIDTH; + mPos++; + mArray[mPos] = Float.floatToRawIntBits(width); + mPos++; + } + + public void setColor(int color) { + mArray[mPos] = COLOR; + mPos++; + mArray[mPos] = color; + mPos++; + } + + /** + * Set the paint's Cap. + * + * @param cap set the paint's line cap style, used whenever the paint's + * style is Stroke or StrokeAndFill. + */ + public void setStrokeCap(int cap) { + mArray[mPos] = STROKE_CAP | (cap << 16); + mPos++; + } + + public void setStyle(int style) { + mArray[mPos] = STYLE | (style << 16); + mPos++; + } + + public void setShader(int shader, String shaderString) { + mArray[mPos] = SHADER | (shader << 16); + mPos++; + } + + public void setAlpha(float alpha) { + mArray[mPos] = ALPHA; + mPos++; + mArray[mPos] = Float.floatToRawIntBits(alpha); + mPos++; + } + + /** + * Set the paint's stroke miter value. This is used to control the behavior + * of miter joins when the joins angle is sharp. This value must be >= 0. + * + * @param miter set the miter limit on the paint, used whenever the paint's + * style is Stroke or StrokeAndFill. + */ + public void setStrokeMiter(float miter) { + mArray[mPos] = STROKE_MITER; + mPos++; + mArray[mPos] = Float.floatToRawIntBits(miter); + mPos++; + } + + /** + * Set the paint's Join. + * + * @param join set the paint's Join, used whenever the paint's style is + * Stroke or StrokeAndFill. + */ + public void setStrokeJoin(int join) { + mArray[mPos] = STROKE_JOIN | (join << 16); + mPos++; + } + + public void setFilterBitmap(boolean filter) { + mArray[mPos] = FILTER_BITMAP | (filter ? (1 << 16) : 0); + mPos++; + } + + /** + * Set or clear the blend mode. A blend mode defines how source pixels + * (generated by a drawing command) are composited with the + * destination pixels + * (content of the render target). + * + * + * @param blendmode The blend mode to be installed in the paint + */ + public void setBlendMode(int blendmode) { + mArray[mPos] = BLEND_MODE | (blendmode << 16); + mPos++; + } + + /** + * Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit + * AntiAliasing smooths out the edges of what is being drawn, but is has + * no impact on the interior of the shape. See setDither() and + * setFilterBitmap() to affect how colors are treated. + * + * @param aa true to set the antialias bit in the flags, false to clear it + */ + public void setAntiAlias(boolean aa) { + mArray[mPos] = ANTI_ALIAS | (((aa) ? 1 : 0) << 16); + mPos++; + } + + public void clear(long mask) { // unused for now + } + + public void reset() { + mPos = 0; + } + + public static String blendModeString(int mode) { + switch (mode) { + case PaintBundle.BLEND_MODE_CLEAR: + return "CLEAR"; + case PaintBundle.BLEND_MODE_SRC: + return "SRC"; + case PaintBundle.BLEND_MODE_DST: + return "DST"; + case PaintBundle.BLEND_MODE_SRC_OVER: + return "SRC_OVER"; + case PaintBundle.BLEND_MODE_DST_OVER: + return "DST_OVER"; + case PaintBundle.BLEND_MODE_SRC_IN: + return "SRC_IN"; + case PaintBundle.BLEND_MODE_DST_IN: + return "DST_IN"; + case PaintBundle.BLEND_MODE_SRC_OUT: + return "SRC_OUT"; + case PaintBundle.BLEND_MODE_DST_OUT: + return "DST_OUT"; + case PaintBundle.BLEND_MODE_SRC_ATOP: + return "SRC_ATOP"; + case PaintBundle.BLEND_MODE_DST_ATOP: + return "DST_ATOP"; + case PaintBundle.BLEND_MODE_XOR: + return "XOR"; + case PaintBundle.BLEND_MODE_PLUS: + return "PLUS"; + case PaintBundle.BLEND_MODE_MODULATE: + return "MODULATE"; + case PaintBundle.BLEND_MODE_SCREEN: + return "SCREEN"; + case PaintBundle.BLEND_MODE_OVERLAY: + return "OVERLAY"; + case PaintBundle.BLEND_MODE_DARKEN: + return "DARKEN"; + case PaintBundle.BLEND_MODE_LIGHTEN: + return "LIGHTEN"; + case PaintBundle.BLEND_MODE_COLOR_DODGE: + return "COLOR_DODGE"; + case PaintBundle.BLEND_MODE_COLOR_BURN: + return "COLOR_BURN"; + case PaintBundle.BLEND_MODE_HARD_LIGHT: + return "HARD_LIGHT"; + case PaintBundle.BLEND_MODE_SOFT_LIGHT: + return "SOFT_LIGHT"; + case PaintBundle.BLEND_MODE_DIFFERENCE: + return "DIFFERENCE"; + case PaintBundle.BLEND_MODE_EXCLUSION: + return "EXCLUSION"; + case PaintBundle.BLEND_MODE_MULTIPLY: + return "MULTIPLY"; + case PaintBundle.BLEND_MODE_HUE: + return "HUE"; + case PaintBundle.BLEND_MODE_SATURATION: + return "SATURATION"; + case PaintBundle.BLEND_MODE_COLOR: + return "COLOR"; + case PaintBundle.BLEND_MODE_LUMINOSITY: + return "LUMINOSITY"; + case PaintBundle.BLEND_MODE_NULL: + return "null"; + case PaintBundle.PORTER_MODE_ADD: + return "ADD"; + } + return "null"; + } + +} + diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java new file mode 100644 index 000000000000..994bf6d7e327 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChangeAdapter.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.paint; + +public class PaintChangeAdapter implements PaintChanges { + + @Override + public void setTextSize(float size) { + + } + + @Override + public void setTypeFace(int fontType, int weight, boolean italic) { + + } + + + @Override + public void setStrokeWidth(float width) { + + } + + @Override + public void setColor(int color) { + + } + + @Override + public void setStrokeCap(int cap) { + + } + + @Override + public void setStyle(int style) { + + } + + @Override + public void setShader(int shader, String shaderString) { + + } + + @Override + public void setImageFilterQuality(int quality) { + + } + + @Override + public void setAlpha(float a) { + + } + + @Override + public void setStrokeMiter(float miter) { + + } + + @Override + public void setStrokeJoin(int join) { + + } + + @Override + public void setFilterBitmap(boolean filter) { + + } + + @Override + public void setBlendMode(int blendmode) { + + } + + @Override + public void setAntiAlias(boolean aa) { + + } + + @Override + public void clear(long mask) { + + } + + @Override + public void setLinearGradient(int[] colorsArray, + float[] stopsArray, + float startX, + float startY, + float endX, + float endY, + int tileMode) { + + } + + @Override + public void setRadialGradient(int[] colorsArray, + float[] stopsArray, + float centerX, + float centerY, + float radius, + int tileMode) { + + } + + @Override + public void setSweepGradient(int[] colorsArray, + float[] stopsArray, + float centerX, + float centerY) { + + } + + @Override + public void setColorFilter(int color, int mode) { + + } + +} diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java new file mode 100644 index 000000000000..87e58ac35930 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/PaintChanges.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.paint; + +public interface PaintChanges { + + + int CLEAR_TEXT_STYLE = 1 << (PaintBundle.TYPEFACE - 1); + int CLEAR_COLOR = 1 << (PaintBundle.COLOR - 1); + int CLEAR_STROKE_WIDTH = 1 << (PaintBundle.STROKE_WIDTH - 1); + int CLEAR_STROKE_MITER = 1 << (PaintBundle.STROKE_MITER - 1); + int CLEAR_CAP = 1 << (PaintBundle.STROKE_CAP - 1); + int CLEAR_STYLE = 1 << (PaintBundle.STYLE - 1); + int CLEAR_SHADER = 1 << (PaintBundle.SHADER - 1); + int CLEAR_IMAGE_FILTER_QUALITY = + 1 << (PaintBundle.IMAGE_FILTER_QUALITY - 1); + int CLEAR_RADIENT = 1 << (PaintBundle.GRADIENT - 1); + int CLEAR_ALPHA = 1 << (PaintBundle.ALPHA - 1); + int CLEAR_COLOR_FILTER = 1 << (PaintBundle.COLOR_FILTER - 1); + int VALID_BITS = 0x1FFF; // only the first 13 bit are valid now + + + void setTextSize(float size); + void setStrokeWidth(float width); + void setColor(int color); + void setStrokeCap(int cap); + void setStyle(int style); + void setShader(int shader, String shaderString); + void setImageFilterQuality(int quality); + void setAlpha(float a); + void setStrokeMiter(float miter); + void setStrokeJoin(int join); + void setFilterBitmap(boolean filter); + void setBlendMode(int mode); + void setAntiAlias(boolean aa); + void clear(long mask); + void setLinearGradient( + int[] colorsArray, + float[] stopsArray, + float startX, + float startY, + float endX, + float endY, + int tileMode + ); + + void setRadialGradient( + int[] colorsArray, + float[] stopsArray, + float centerX, + float centerY, + float radius, + int tileMode + ); + + void setSweepGradient( + int[] colorsArray, + float[] stopsArray, + float centerX, + float centerY + ); + + + void setColorFilter(int color, int mode); + + void setTypeFace(int fontType, int weight, boolean italic); +} + diff --git a/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java new file mode 100644 index 000000000000..1c0bec76bb62 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/core/operations/paint/TextPaint.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.core.operations.paint; + +public interface TextPaint { + void setARGB(int a, int r, int g, int b); + + void setDither(boolean dither); + + void setElegantTextHeight(boolean elegant); + + void setEndHyphenEdit(int endHyphen); + + void setFakeBoldText(boolean fakeBoldText); + + void setFlags(int flags); + + void setFontFeatureSettings(String settings); + + void setHinting(int mode); + + void setLetterSpacing(float letterSpacing); + + void setLinearText(boolean linearText); + + void setShadowLayer(float radius, float dx, float dy, int shadowColor); + + void setStartHyphenEdit(int startHyphen); + + void setStrikeThruText(boolean strikeThruText); + + void setStrokeCap(int cap); + + void setSubpixelText(boolean subpixelText); + + void setTextAlign(int align); + + void setTextLocale(int locale); + + void setTextLocales(int localesArray); + + void setTextScaleX(float scaleX); + + void setTextSize(float textSize); + + void setTextSkewX(float skewX); + + void setUnderlineText(boolean underlineText); + + void setWordSpacing(float wordSpacing); +} diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java index 3799cf6baac9..d0d6e6982a16 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidPaintContext.java @@ -16,12 +16,25 @@ package com.android.internal.widget.remotecompose.player.platform; import android.graphics.Bitmap; +import android.graphics.BlendMode; import android.graphics.Canvas; +import android.graphics.LinearGradient; import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.RadialGradient; import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.SweepGradient; +import android.graphics.Typeface; import com.android.internal.widget.remotecompose.core.PaintContext; import com.android.internal.widget.remotecompose.core.RemoteContext; +import com.android.internal.widget.remotecompose.core.operations.ClipPath; +import com.android.internal.widget.remotecompose.core.operations.paint.PaintBundle; +import com.android.internal.widget.remotecompose.core.operations.paint.PaintChanges; /** * An implementation of PaintContext for the Android Canvas. @@ -71,7 +84,8 @@ public class AndroidPaintContext extends PaintContext { int cdId) { AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext; if (androidContext.mRemoteComposeState.containsId(imageId)) { - Bitmap bitmap = (Bitmap) androidContext.mRemoteComposeState.getFromId(imageId); + Bitmap bitmap = (Bitmap) androidContext.mRemoteComposeState + .getFromId(imageId); mCanvas.drawBitmap( bitmap, new Rect(srcLeft, srcTop, srcRight, srcBottom), @@ -89,5 +103,501 @@ public class AndroidPaintContext extends PaintContext { public void translate(float translateX, float translateY) { mCanvas.translate(translateX, translateY); } + + @Override + public void drawArc(float left, + float top, + float right, + float bottom, + float startAngle, + float sweepAngle) { + mCanvas.drawArc(left, top, right, bottom, startAngle, + sweepAngle, true, mPaint); + } + + @Override + public void drawBitmap(int id, + float left, + float top, + float right, + float bottom) { + AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext; + if (androidContext.mRemoteComposeState.containsId(id)) { + Bitmap bitmap = + (Bitmap) androidContext.mRemoteComposeState.getFromId(id); + Rect src = new Rect(0, 0, + bitmap.getWidth(), bitmap.getHeight()); + RectF dst = new RectF(left, top, right, bottom); + mCanvas.drawBitmap(bitmap, src, dst, mPaint); + } + } + + @Override + public void drawCircle(float centerX, float centerY, float radius) { + mCanvas.drawCircle(centerX, centerY, radius, mPaint); + } + + @Override + public void drawLine(float x1, float y1, float x2, float y2) { + mCanvas.drawLine(x1, y1, x2, y2, mPaint); + } + + @Override + public void drawOval(float left, float top, float right, float bottom) { + mCanvas.drawOval(left, top, right, bottom, mPaint); + } + + @Override + public void drawPath(int id, float start, float end) { + mCanvas.drawPath(getPath(id, start, end), mPaint); + } + + @Override + public void drawRect(float left, float top, float right, float bottom) { + mCanvas.drawRect(left, top, right, bottom, mPaint); + } + + @Override + public void drawRoundRect(float left, + float top, + float right, + float bottom, + float radiusX, + float radiusY) { + mCanvas.drawRoundRect(left, top, right, bottom, + radiusX, radiusY, mPaint); + } + + @Override + public void drawTextOnPath(int textId, + int pathId, + float hOffset, + float vOffset) { + mCanvas.drawTextOnPath(getText(textId), getPath(pathId, 0, 1), hOffset, vOffset, mPaint); + } + + @Override + public void drawTextRun(int textID, + int start, + int end, + int contextStart, + int contextEnd, + float x, + float y, + boolean rtl) { + String textToPaint = getText(textID).substring(start, end); + mCanvas.drawText(textToPaint, x, y, mPaint); + } + + @Override + public void drawTweenPath(int path1Id, + int path2Id, + float tween, + float start, + float end) { + mCanvas.drawPath(getPath(path1Id, path2Id, tween, start, end), mPaint); + } + + private static PorterDuff.Mode origamiToPorterDuffMode(int mode) { + switch (mode) { + case PaintBundle.BLEND_MODE_CLEAR: + return PorterDuff.Mode.CLEAR; + case PaintBundle.BLEND_MODE_SRC: + return PorterDuff.Mode.SRC; + case PaintBundle.BLEND_MODE_DST: + return PorterDuff.Mode.DST; + case PaintBundle.BLEND_MODE_SRC_OVER: + return PorterDuff.Mode.SRC_OVER; + case PaintBundle.BLEND_MODE_DST_OVER: + return PorterDuff.Mode.DST_OVER; + case PaintBundle.BLEND_MODE_SRC_IN: + return PorterDuff.Mode.SRC_IN; + case PaintBundle.BLEND_MODE_DST_IN: + return PorterDuff.Mode.DST_IN; + case PaintBundle.BLEND_MODE_SRC_OUT: + return PorterDuff.Mode.SRC_OUT; + case PaintBundle.BLEND_MODE_DST_OUT: + return PorterDuff.Mode.DST_OUT; + case PaintBundle.BLEND_MODE_SRC_ATOP: + return PorterDuff.Mode.SRC_ATOP; + case PaintBundle.BLEND_MODE_DST_ATOP: + return PorterDuff.Mode.DST_ATOP; + case PaintBundle.BLEND_MODE_XOR: + return PorterDuff.Mode.XOR; + case PaintBundle.BLEND_MODE_SCREEN: + return PorterDuff.Mode.SCREEN; + case PaintBundle.BLEND_MODE_OVERLAY: + return PorterDuff.Mode.OVERLAY; + case PaintBundle.BLEND_MODE_DARKEN: + return PorterDuff.Mode.DARKEN; + case PaintBundle.BLEND_MODE_LIGHTEN: + return PorterDuff.Mode.LIGHTEN; + case PaintBundle.BLEND_MODE_MULTIPLY: + return PorterDuff.Mode.MULTIPLY; + case PaintBundle.PORTER_MODE_ADD: + return PorterDuff.Mode.ADD; + } + return PorterDuff.Mode.SRC_OVER; + } + + public static BlendMode origamiToBlendMode(int mode) { + switch (mode) { + case PaintBundle.BLEND_MODE_CLEAR: + return BlendMode.CLEAR; + case PaintBundle.BLEND_MODE_SRC: + return BlendMode.SRC; + case PaintBundle.BLEND_MODE_DST: + return BlendMode.DST; + case PaintBundle.BLEND_MODE_SRC_OVER: + return BlendMode.SRC_OVER; + case PaintBundle.BLEND_MODE_DST_OVER: + return BlendMode.DST_OVER; + case PaintBundle.BLEND_MODE_SRC_IN: + return BlendMode.SRC_IN; + case PaintBundle.BLEND_MODE_DST_IN: + return BlendMode.DST_IN; + case PaintBundle.BLEND_MODE_SRC_OUT: + return BlendMode.SRC_OUT; + case PaintBundle.BLEND_MODE_DST_OUT: + return BlendMode.DST_OUT; + case PaintBundle.BLEND_MODE_SRC_ATOP: + return BlendMode.SRC_ATOP; + case PaintBundle.BLEND_MODE_DST_ATOP: + return BlendMode.DST_ATOP; + case PaintBundle.BLEND_MODE_XOR: + return BlendMode.XOR; + case PaintBundle.BLEND_MODE_PLUS: + return BlendMode.PLUS; + case PaintBundle.BLEND_MODE_MODULATE: + return BlendMode.MODULATE; + case PaintBundle.BLEND_MODE_SCREEN: + return BlendMode.SCREEN; + case PaintBundle.BLEND_MODE_OVERLAY: + return BlendMode.OVERLAY; + case PaintBundle.BLEND_MODE_DARKEN: + return BlendMode.DARKEN; + case PaintBundle.BLEND_MODE_LIGHTEN: + return BlendMode.LIGHTEN; + case PaintBundle.BLEND_MODE_COLOR_DODGE: + return BlendMode.COLOR_DODGE; + case PaintBundle.BLEND_MODE_COLOR_BURN: + return BlendMode.COLOR_BURN; + case PaintBundle.BLEND_MODE_HARD_LIGHT: + return BlendMode.HARD_LIGHT; + case PaintBundle.BLEND_MODE_SOFT_LIGHT: + return BlendMode.SOFT_LIGHT; + case PaintBundle.BLEND_MODE_DIFFERENCE: + return BlendMode.DIFFERENCE; + case PaintBundle.BLEND_MODE_EXCLUSION: + return BlendMode.EXCLUSION; + case PaintBundle.BLEND_MODE_MULTIPLY: + return BlendMode.MULTIPLY; + case PaintBundle.BLEND_MODE_HUE: + return BlendMode.HUE; + case PaintBundle.BLEND_MODE_SATURATION: + return BlendMode.SATURATION; + case PaintBundle.BLEND_MODE_COLOR: + return BlendMode.COLOR; + case PaintBundle.BLEND_MODE_LUMINOSITY: + return BlendMode.LUMINOSITY; + case PaintBundle.BLEND_MODE_NULL: + return null; + } + return null; + } + + @Override + public void applyPaint(PaintBundle mPaintData) { + mPaintData.applyPaintChange(new PaintChanges() { + @Override + public void setTextSize(float size) { + mPaint.setTextSize(size); + } + + @Override + public void setTypeFace(int fontType, int weight, boolean italic) { + int[] type = new int[]{Typeface.NORMAL, Typeface.BOLD, + Typeface.ITALIC, Typeface.BOLD_ITALIC}; + + switch (fontType) { + case PaintBundle.FONT_TYPE_DEFAULT: { + if (weight == 400 && !italic) { // for normal case + mPaint.setTypeface(Typeface.DEFAULT); + } else { + mPaint.setTypeface(Typeface.create(Typeface.DEFAULT, + weight, italic)); + } + break; + } + case PaintBundle.FONT_TYPE_SERIF: { + if (weight == 400 && !italic) { // for normal case + mPaint.setTypeface(Typeface.SERIF); + } else { + mPaint.setTypeface(Typeface.create(Typeface.SERIF, + weight, italic)); + } + break; + } + case PaintBundle.FONT_TYPE_SANS_SERIF: { + if (weight == 400 && !italic) { // for normal case + mPaint.setTypeface(Typeface.SANS_SERIF); + } else { + mPaint.setTypeface( + Typeface.create(Typeface.SANS_SERIF, + weight, italic)); + } + break; + } + case PaintBundle.FONT_TYPE_MONOSPACE: { + if (weight == 400 && !italic) { // for normal case + mPaint.setTypeface(Typeface.MONOSPACE); + } else { + mPaint.setTypeface( + Typeface.create(Typeface.MONOSPACE, + weight, italic)); + } + + break; + } + } + + + } + + + @Override + public void setStrokeWidth(float width) { + mPaint.setStrokeWidth(width); + } + + @Override + public void setColor(int color) { + mPaint.setColor(color); + } + + @Override + public void setStrokeCap(int cap) { + mPaint.setStrokeCap(Paint.Cap.values()[cap]); + } + + @Override + public void setStyle(int style) { + mPaint.setStyle(Paint.Style.values()[style]); + } + + @Override + public void setShader(int shader, String shaderString) { + + } + + @Override + public void setImageFilterQuality(int quality) { + System.out.println(">>>>>>>>>>>> "); + } + + @Override + public void setBlendMode(int mode) { + mPaint.setBlendMode(origamiToBlendMode(mode)); + } + + @Override + public void setAlpha(float a) { + mPaint.setAlpha((int) (255 * a)); + } + + @Override + public void setStrokeMiter(float miter) { + mPaint.setStrokeMiter(miter); + } + + @Override + public void setStrokeJoin(int join) { + mPaint.setStrokeJoin(Paint.Join.values()[join]); + } + + @Override + public void setFilterBitmap(boolean filter) { + mPaint.setFilterBitmap(filter); + } + + + @Override + public void setAntiAlias(boolean aa) { + mPaint.setAntiAlias(aa); + } + + @Override + public void clear(long mask) { + if (true) return; + long m = mask; + int k = 1; + while (m > 0) { + if ((m & 1) == 1L) { + switch (k) { + + case PaintBundle.COLOR_FILTER: + mPaint.setColorFilter(null); + System.out.println(">>>>>>>>>>>>> CLEAR!!!!"); + break; + } + } + k++; + m = m >> 1; + } + } + + Shader.TileMode[] mTilesModes = new Shader.TileMode[]{ + Shader.TileMode.CLAMP, + Shader.TileMode.REPEAT, + Shader.TileMode.MIRROR}; + + + @Override + public void setLinearGradient(int[] colors, + float[] stops, + float startX, + float startY, + float endX, + float endY, + int tileMode) { + mPaint.setShader(new LinearGradient(startX, + startY, + endX, + endY, colors, stops, mTilesModes[tileMode])); + + } + + @Override + public void setRadialGradient(int[] colors, + float[] stops, + float centerX, + float centerY, + float radius, + int tileMode) { + mPaint.setShader(new RadialGradient(centerX, centerY, radius, + colors, stops, mTilesModes[tileMode])); + } + + @Override + public void setSweepGradient(int[] colors, + float[] stops, + float centerX, + float centerY) { + mPaint.setShader(new SweepGradient(centerX, centerY, colors, stops)); + + } + + @Override + public void setColorFilter(int color, int mode) { + PorterDuff.Mode pmode = origamiToPorterDuffMode(mode); + System.out.println("setting color filter to " + pmode.name()); + if (pmode != null) { + mPaint.setColorFilter( + new PorterDuffColorFilter(color, pmode)); + } + } + }); + } + + @Override + public void mtrixScale(float scaleX, + float scaleY, + float centerX, + float centerY) { + if (Float.isNaN(centerX)) { + mCanvas.scale(scaleX, scaleY); + } else { + mCanvas.scale(scaleX, scaleY, centerX, centerY); + } + } + + @Override + public void matrixTranslate(float translateX, float translateY) { + mCanvas.translate(translateX, translateY); + } + + @Override + public void matrixSkew(float skewX, float skewY) { + mCanvas.skew(skewX, skewY); + } + + @Override + public void matrixRotate(float rotate, float pivotX, float pivotY) { + if (Float.isNaN(pivotX)) { + mCanvas.rotate(rotate); + } else { + mCanvas.rotate(rotate, pivotX, pivotY); + + } + } + + @Override + public void matrixSave() { + mCanvas.save(); + } + + @Override + public void matrixRestore() { + mCanvas.restore(); + } + + @Override + public void clipRect(float left, float top, float right, float bottom) { + mCanvas.clipRect(left, top, right, bottom); + } + + @Override + public void clipPath(int pathId, int regionOp) { + Path path = getPath(pathId, 0, 1); + if (regionOp == ClipPath.DIFFERENCE) { + mCanvas.clipOutPath(path); // DIFFERENCE + } else { + mCanvas.clipPath(path); // INTERSECT + } + } + + private Path getPath(int path1Id, + int path2Id, + float tween, + float start, + float end) { + if (tween == 0.0f) { + return getPath(path1Id, start, end); + } + if (tween == 1.0f) { + return getPath(path2Id, start, end); + } + AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext; + float[] data1 = + (float[]) androidContext.mRemoteComposeState.getFromId(path1Id); + float[] data2 = + (float[]) androidContext.mRemoteComposeState.getFromId(path2Id); + float[] tmp = new float[data2.length]; + for (int i = 0; i < tmp.length; i++) { + if (Float.isNaN(data1[i]) || Float.isNaN(data2[i])) { + tmp[i] = data1[i]; + } else { + tmp[i] = (data2[i] - data1[i]) * tween + data1[i]; + } + } + Path path = new Path(); + FloatsToPath.genPath(path, tmp, start, end); + return path; + } + + private Path getPath(int id, float start, float end) { + AndroidRemoteContext androidContext = (AndroidRemoteContext) mContext; + Path path = new Path(); + if (androidContext.mRemoteComposeState.containsId(id)) { + float[] data = + (float[]) androidContext.mRemoteComposeState.getFromId(id); + FloatsToPath.genPath(path, data, start, end); + } + return path; + } + + private String getText(int id) { + return (String) mContext.mRemoteComposeState.getFromId(id); + } } diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java index ce15855fecfc..270e96f11942 100644 --- a/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/AndroidRemoteContext.java @@ -43,6 +43,13 @@ class AndroidRemoteContext extends RemoteContext { // Data handling /////////////////////////////////////////////////////////////////////////////////////////////// + @Override + public void loadPathData(int instanceId, float[] floatPath) { + if (!mRemoteComposeState.containsId(instanceId)) { + mRemoteComposeState.cache(instanceId, floatPath); + } + } + /** * Decode a byte array into an image and cache it using the given imageId * diff --git a/core/java/com/android/internal/widget/remotecompose/player/platform/FloatsToPath.java b/core/java/com/android/internal/widget/remotecompose/player/platform/FloatsToPath.java new file mode 100644 index 000000000000..2d766f8da295 --- /dev/null +++ b/core/java/com/android/internal/widget/remotecompose/player/platform/FloatsToPath.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.internal.widget.remotecompose.player.platform; + +import static com.android.internal.widget.remotecompose.core.operations.Utils.idFromNan; + +import android.graphics.Path; +import android.graphics.PathMeasure; +import android.os.Build; + +import com.android.internal.widget.remotecompose.core.operations.PathData; + +public class FloatsToPath { + public static void genPath(Path retPath, + float[] floatPath, + float start, + float stop) { + int i = 0; + Path path = new Path(); // todo this should be cached for performance + while (i < floatPath.length) { + switch (idFromNan(floatPath[i])) { + case PathData.MOVE: { + i++; + path.moveTo(floatPath[i + 0], floatPath[i + 1]); + i += 2; + } + break; + case PathData.LINE: { + i += 3; + path.lineTo(floatPath[i + 0], floatPath[i + 1]); + i += 2; + } + break; + case PathData.QUADRATIC: { + i += 3; + path.quadTo( + floatPath[i + 0], + floatPath[i + 1], + floatPath[i + 2], + floatPath[i + 3] + ); + i += 4; + + } + break; + case PathData.CONIC: { + i += 3; + if (Build.VERSION.SDK_INT >= 34) { + path.conicTo( + floatPath[i + 0], floatPath[i + 1], + floatPath[i + 2], floatPath[i + 3], + floatPath[i + 4] + ); + } + i += 5; + } + break; + case PathData.CUBIC: { + i += 3; + path.cubicTo( + floatPath[i + 0], floatPath[i + 1], + floatPath[i + 2], floatPath[i + 3], + floatPath[i + 4], floatPath[i + 5] + ); + i += 6; + } + break; + case PathData.CLOSE: { + + path.close(); + i++; + } + break; + case PathData.DONE: { + i++; + } + break; + default: { + System.err.println(" Odd command " + + idFromNan(floatPath[i])); + } + } + } + + retPath.reset(); + if (start > 0f || stop < 1f) { + if (start < stop) { + + PathMeasure measure = new PathMeasure(); // todo cached + measure.setPath(path, false); + float len = measure.getLength(); + float scaleStart = Math.max(start, 0f) * len; + float scaleStop = Math.min(stop, 1f) * len; + measure.getSegment(scaleStart, scaleStop, retPath, + true); + } + } else { + + retPath.addPath(path); + } + } +} |