• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.internal.widget.remotecompose.core.operations;
17 
18 import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT;
19 import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.INT_ARRAY;
20 import static com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation.SHORT;
21 
22 import android.annotation.NonNull;
23 
24 import com.android.internal.widget.remotecompose.core.Operation;
25 import com.android.internal.widget.remotecompose.core.Operations;
26 import com.android.internal.widget.remotecompose.core.RemoteContext;
27 import com.android.internal.widget.remotecompose.core.SerializableToString;
28 import com.android.internal.widget.remotecompose.core.WireBuffer;
29 import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder;
30 import com.android.internal.widget.remotecompose.core.documentation.DocumentedOperation;
31 import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer;
32 import com.android.internal.widget.remotecompose.core.serialize.MapSerializer;
33 import com.android.internal.widget.remotecompose.core.serialize.Serializable;
34 
35 import java.util.List;
36 
37 /**
38  * Operation to deal with bitmap data On getting an Image during a draw call the bitmap is
39  * compressed and saved in playback the image is decompressed
40  */
41 public class BitmapData extends Operation implements SerializableToString, Serializable {
42     private static final int OP_CODE = Operations.DATA_BITMAP;
43     private static final String CLASS_NAME = "BitmapData";
44     public final int mImageId;
45     int mImageWidth;
46     int mImageHeight;
47     short mType;
48     short mEncoding;
49     @NonNull byte[] mBitmap;
50 
51     /** The max size of width or height */
52     public static final int MAX_IMAGE_DIMENSION = 8000;
53 
54     /** The data is encoded in the file (default) */
55     public static final short ENCODING_INLINE = 0;
56 
57     /** The data is encoded in the url */
58     public static final short ENCODING_URL = 1;
59 
60     /** The data is encoded as a reference to file */
61     public static final short ENCODING_FILE = 2;
62 
63     /** The data is encoded as PNG_8888 (default) */
64     public static final short TYPE_PNG_8888 = 0;
65 
66     /** The data is encoded as PNG */
67     public static final short TYPE_PNG = 1;
68 
69     /** The data is encoded as RAW 8 bit */
70     public static final short TYPE_RAW8 = 2;
71 
72     /** The data is encoded as RAW 8888 bit */
73     public static final short TYPE_RAW8888 = 3;
74 
75     /** The data is encoded as PNG_8888 but decoded as ALPHA_8 */
76     public static final short TYPE_PNG_ALPHA_8 = 4;
77 
78     /**
79      * create a bitmap structure
80      *
81      * @param imageId the id to store the image
82      * @param width the width of the image
83      * @param height the height of the image
84      * @param bitmap the data
85      */
BitmapData(int imageId, int width, int height, @NonNull byte[] bitmap)86     public BitmapData(int imageId, int width, int height, @NonNull byte[] bitmap) {
87         this.mImageId = imageId;
88         this.mImageWidth = width;
89         this.mImageHeight = height;
90         this.mBitmap = bitmap;
91     }
92 
93     /**
94      * Update the bitmap data
95      *
96      * @param from the bitmap to copy
97      */
update(BitmapData from)98     public void update(BitmapData from) {
99         this.mImageWidth = from.mImageWidth;
100         this.mImageHeight = from.mImageHeight;
101         this.mBitmap = from.mBitmap;
102         this.mType = from.mType;
103         this.mEncoding = from.mEncoding;
104     }
105 
106     /**
107      * The width of the image
108      *
109      * @return the width
110      */
getWidth()111     public int getWidth() {
112         return mImageWidth;
113     }
114 
115     /**
116      * The height of the image
117      *
118      * @return the height
119      */
getHeight()120     public int getHeight() {
121         return mImageHeight;
122     }
123 
124     @Override
write(@onNull WireBuffer buffer)125     public void write(@NonNull WireBuffer buffer) {
126         apply(buffer, mImageId, mImageWidth, mImageHeight, mBitmap);
127     }
128 
129     @NonNull
130     @Override
toString()131     public String toString() {
132         return "BITMAP DATA " + mImageId;
133     }
134 
135     /**
136      * The name of the class
137      *
138      * @return the name
139      */
140     @NonNull
name()141     public static String name() {
142         return CLASS_NAME;
143     }
144 
145     /**
146      * The OP_CODE for this command
147      *
148      * @return the opcode
149      */
id()150     public static int id() {
151         return OP_CODE;
152     }
153 
154     /**
155      * The type of the image
156      *
157      * @return the type of the image
158      */
getType()159     public int getType() {
160         return mType;
161     }
162 
163     /**
164      * Add the image to the document
165      *
166      * @param buffer document to write to
167      * @param imageId the id the image will be stored under
168      * @param width the width of the image
169      * @param height the height of the image
170      * @param bitmap the data used to store/encode the image
171      */
apply( @onNull WireBuffer buffer, int imageId, int width, int height, @NonNull byte[] bitmap)172     public static void apply(
173             @NonNull WireBuffer buffer,
174             int imageId,
175             int width,
176             int height,
177             @NonNull byte[] bitmap) {
178         buffer.start(OP_CODE);
179         buffer.writeInt(imageId);
180         buffer.writeInt(width);
181         buffer.writeInt(height);
182         buffer.writeBuffer(bitmap);
183     }
184 
185     /**
186      * Add the image to the document (using the ehanced encoding)
187      *
188      * @param buffer document to write to
189      * @param imageId the id the image will be stored under
190      * @param type the type of image
191      * @param width the width of the image
192      * @param encoding the encoding
193      * @param height the height of the image
194      * @param bitmap the data used to store/encode the image
195      */
apply( @onNull WireBuffer buffer, int imageId, short type, short width, short encoding, short height, @NonNull byte[] bitmap)196     public static void apply(
197             @NonNull WireBuffer buffer,
198             int imageId,
199             short type,
200             short width,
201             short encoding,
202             short height,
203             @NonNull byte[] bitmap) {
204         buffer.start(OP_CODE);
205         buffer.writeInt(imageId);
206         int w = (((int) type) << 16) | width;
207         int h = (((int) encoding) << 16) | height;
208         buffer.writeInt(w);
209         buffer.writeInt(h);
210         buffer.writeBuffer(bitmap);
211     }
212 
213     /**
214      * Read this operation and add it to the list of operations
215      *
216      * @param buffer the buffer to read
217      * @param operations the list of operations that will be added to
218      */
read(@onNull WireBuffer buffer, @NonNull List<Operation> operations)219     public static void read(@NonNull WireBuffer buffer, @NonNull List<Operation> operations) {
220         int imageId = buffer.readInt();
221         int width = buffer.readInt();
222         int height = buffer.readInt();
223         int type;
224         if (width > 0xffff) {
225             type = width >> 16;
226             width = width & 0xffff;
227         } else {
228             type = TYPE_PNG_8888;
229         }
230 
231         int encoding;
232         if (height > 0xffff) {
233             encoding = height >> 16;
234             height = height & 0xffff;
235         } else {
236             encoding = ENCODING_INLINE;
237         }
238         if (width < 1
239                 || height < 1
240                 || height > MAX_IMAGE_DIMENSION
241                 || width > MAX_IMAGE_DIMENSION) {
242             throw new RuntimeException("Dimension of image is invalid " + width + "x" + height);
243         }
244         byte[] bitmap = buffer.readBuffer();
245         BitmapData bitmapData = new BitmapData(imageId, width, height, bitmap);
246         bitmapData.mType = (short) type;
247         bitmapData.mEncoding = (short) encoding;
248         operations.add(bitmapData);
249     }
250 
251     /**
252      * Populate the documentation with a description of this operation
253      *
254      * @param doc to append the description to.
255      */
documentation(@onNull DocumentationBuilder doc)256     public static void documentation(@NonNull DocumentationBuilder doc) {
257         doc.operation("Data Operations", OP_CODE, CLASS_NAME)
258                 .description("Bitmap data")
259                 .field(DocumentedOperation.INT, "id", "id of bitmap data")
260                 .field(SHORT, "type", "width of the image")
261                 .field(SHORT, "width", "width of the image")
262                 .field(SHORT, "encoding", "height of the image")
263                 .field(INT, "width", "width of the image")
264                 .field(SHORT, "height", "height of the image")
265                 .field(INT_ARRAY, "values", "length", "Array of ints");
266     }
267 
268     @Override
apply(@onNull RemoteContext context)269     public void apply(@NonNull RemoteContext context) {
270         context.putObject(mImageId, this);
271         context.loadBitmap(mImageId, mEncoding, mType, mImageWidth, mImageHeight, mBitmap);
272     }
273 
274     @NonNull
275     @Override
deepToString(@onNull String indent)276     public String deepToString(@NonNull String indent) {
277         return indent + toString();
278     }
279 
280     @Override
serializeToString(int indent, @NonNull StringSerializer serializer)281     public void serializeToString(int indent, @NonNull StringSerializer serializer) {
282         serializer.append(
283                 indent,
284                 CLASS_NAME + " id " + mImageId + " (" + mImageWidth + "x" + mImageHeight + ")");
285     }
286 
287     @Override
serialize(MapSerializer serializer)288     public void serialize(MapSerializer serializer) {
289         serializer
290                 .addType(CLASS_NAME)
291                 .add("imageId", mImageId)
292                 .add("imageWidth", mImageWidth)
293                 .add("imageHeight", mImageHeight)
294                 .add("imageType", getImageTypeString(mType))
295                 .add("encoding", getEncodingString(mEncoding));
296     }
297 
getEncodingString(short encoding)298     private String getEncodingString(short encoding) {
299         switch (encoding) {
300             case ENCODING_INLINE:
301                 return "ENCODING_INLINE";
302             case ENCODING_URL:
303                 return "ENCODING_URL";
304             case ENCODING_FILE:
305                 return "ENCODING_FILE";
306             default:
307                 return "ENCODING_INVALID";
308         }
309     }
310 
getImageTypeString(short type)311     private String getImageTypeString(short type) {
312         switch (type) {
313             case TYPE_PNG_8888:
314                 return "TYPE_PNG_8888";
315             case TYPE_PNG:
316                 return "TYPE_PNG";
317             case TYPE_RAW8:
318                 return "TYPE_RAW8";
319             case TYPE_RAW8888:
320                 return "TYPE_RAW8888";
321             case TYPE_PNG_ALPHA_8:
322                 return "TYPE_PNG_ALPHA_8";
323             default:
324                 return "TYPE_INVALID";
325         }
326     }
327 }
328