1 /* 2 * Copyright (C) 2024 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.layout.modifiers; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 21 import com.android.internal.widget.remotecompose.core.Operation; 22 import com.android.internal.widget.remotecompose.core.Operations; 23 import com.android.internal.widget.remotecompose.core.PaintContext; 24 import com.android.internal.widget.remotecompose.core.RemoteContext; 25 import com.android.internal.widget.remotecompose.core.WireBuffer; 26 import com.android.internal.widget.remotecompose.core.documentation.DocumentationBuilder; 27 import com.android.internal.widget.remotecompose.core.operations.layout.AnimatableValue; 28 import com.android.internal.widget.remotecompose.core.operations.layout.Component; 29 import com.android.internal.widget.remotecompose.core.operations.utilities.StringSerializer; 30 import com.android.internal.widget.remotecompose.core.serialize.MapSerializer; 31 import com.android.internal.widget.remotecompose.core.serialize.SerializeTags; 32 33 import java.util.HashMap; 34 import java.util.List; 35 36 /** Represents a graphics layer modifier. */ 37 public class GraphicsLayerModifierOperation extends DecoratorModifierOperation { 38 private static final int OP_CODE = Operations.MODIFIER_GRAPHICS_LAYER; 39 public static final String CLASS_NAME = "GraphicsLayerModifierOperation"; 40 41 public static final int SCALE_X = 0; 42 public static final int SCALE_Y = 1; 43 public static final int ROTATION_X = 2; 44 public static final int ROTATION_Y = 3; 45 public static final int ROTATION_Z = 4; 46 public static final int TRANSFORM_ORIGIN_X = 5; 47 public static final int TRANSFORM_ORIGIN_Y = 6; 48 public static final int TRANSLATION_X = 7; 49 public static final int TRANSLATION_Y = 8; 50 public static final int TRANSLATION_Z = 9; 51 public static final int SHADOW_ELEVATION = 10; 52 public static final int ALPHA = 11; 53 public static final int CAMERA_DISTANCE = 12; 54 public static final int COMPOSITING_STRATEGY = 13; 55 public static final int SPOT_SHADOW_COLOR = 14; 56 public static final int AMBIENT_SHADOW_COLOR = 15; 57 public static final int HAS_BLUR = 16; 58 public static final int BLUR_RADIUS_X = 17; 59 public static final int BLUR_RADIUS_Y = 18; 60 public static final int BLUR_TILE_MODE = 19; 61 public static final int SHAPE = 20; 62 public static final int SHAPE_RADIUS = 21; 63 64 public static final int SHAPE_RECT = 0; 65 public static final int SHAPE_ROUND_RECT = 1; 66 public static final int SHAPE_CIRCLE = 2; 67 68 public static final int TILE_MODE_CLAMP = 0; 69 public static final int TILE_MODE_REPEATED = 1; 70 public static final int TILE_MODE_MIRROR = 2; 71 public static final int TILE_MODE_DECAL = 3; 72 73 /** The object is an integer */ 74 private static final short DATA_TYPE_INT = 0; 75 76 /** The object is an float */ 77 private static final short DATA_TYPE_FLOAT = 1; 78 79 AttributeValue[] mValues = { 80 new AttributeValue(SCALE_X, "SCALE_X", 1f), 81 new AttributeValue(SCALE_Y, "SCALE_Y", 1f), 82 new AttributeValue(ROTATION_X, "ROTATION_X", 0f), 83 new AttributeValue(ROTATION_Y, "ROTATION_Y", 0f), 84 new AttributeValue(ROTATION_Z, "ROTATION_Z", 0f), 85 new AttributeValue(TRANSFORM_ORIGIN_X, "TRANSFORM_ORIGIN_X", 0f), 86 new AttributeValue(TRANSFORM_ORIGIN_Y, "TRANSFORM_ORIGIN_Y", 0f), 87 new AttributeValue(TRANSLATION_X, "TRANSLATION_X", 0f), 88 new AttributeValue(TRANSLATION_Y, "TRANSLATION_Y", 0f), 89 new AttributeValue(TRANSLATION_Z, "TRANSLATION_Z", 0f), 90 new AttributeValue(SHADOW_ELEVATION, "SHADOW_ELEVATION", 0f), 91 new AttributeValue(ALPHA, "ALPHA", 1f), 92 new AttributeValue(CAMERA_DISTANCE, "CAMERA_DISTANCE", 8f), 93 new AttributeValue(COMPOSITING_STRATEGY, "COMPOSITING_STRATEGY", 0), 94 new AttributeValue(SPOT_SHADOW_COLOR, "SPOT_SHADOW_COLOR", 0), 95 new AttributeValue(AMBIENT_SHADOW_COLOR, "AMBIENT_SHADOW_COLOR", 0), 96 new AttributeValue(HAS_BLUR, "HAS_BLUR", 0), 97 new AttributeValue(BLUR_RADIUS_X, "BLUR_RADIUS_X", 0f), 98 new AttributeValue(BLUR_RADIUS_Y, "BLUR_RADIUS_Y", 0f), 99 new AttributeValue(BLUR_TILE_MODE, "BLUR_TILE_MODE", TILE_MODE_CLAMP), 100 new AttributeValue(SHAPE, "SHAPE", -1), 101 new AttributeValue(SHAPE_RADIUS, "SHAPE_RADIUS", 0f), 102 }; 103 104 boolean mHasBlurEffect = false; 105 106 /** 107 * Fill in the hashmap with the attributes values 108 * 109 * @param attributes 110 */ fillInAttributes(HashMap<Integer, Object> attributes)111 public void fillInAttributes(HashMap<Integer, Object> attributes) { 112 for (int i = 0; i < mValues.length; i++) { 113 if (mValues[i].needsToWrite()) { 114 attributes.put(i, mValues[i].getObjectValue()); 115 } 116 } 117 } 118 119 static final int FLOAT_VALUE = 0; 120 static final int INT_VALUE = 1; 121 122 /** Utility class to manage attributes */ 123 static class AttributeValue { 124 String mName; 125 int mId; 126 @Nullable AnimatableValue mAnimatableValue; 127 float mDefaultValue = 0f; 128 int mIntValue = 0; 129 int mIntDefaultValue = 0; 130 int mType = FLOAT_VALUE; 131 AttributeValue(int id, String name, float defaultValue)132 AttributeValue(int id, String name, float defaultValue) { 133 mId = id; 134 mName = name; 135 mDefaultValue = defaultValue; 136 mType = FLOAT_VALUE; 137 } 138 AttributeValue(int id, String name, int defaultValue)139 AttributeValue(int id, String name, int defaultValue) { 140 mId = id; 141 mName = name; 142 mIntDefaultValue = defaultValue; 143 mType = INT_VALUE; 144 } 145 getValue()146 public float getValue() { 147 if (mType == FLOAT_VALUE) { 148 if (mAnimatableValue != null) { 149 return mAnimatableValue.getValue(); 150 } 151 return mDefaultValue; 152 } else { 153 return mIntValue; 154 } 155 } 156 getIntValue()157 public int getIntValue() { 158 if (mType == FLOAT_VALUE) { 159 if (mAnimatableValue != null) { 160 return (int) mAnimatableValue.getValue(); 161 } 162 } else if (mType == INT_VALUE) { 163 return mIntValue; 164 } 165 return 0; 166 } 167 evaluate(PaintContext context)168 public void evaluate(PaintContext context) { 169 if (mAnimatableValue != null) { 170 mAnimatableValue.evaluate(context); 171 } 172 } 173 needsToWrite()174 public boolean needsToWrite() { 175 if (mType == FLOAT_VALUE) { 176 if (mAnimatableValue != null) { 177 return mAnimatableValue.getValue() != mDefaultValue; 178 } 179 return false; 180 } else if (mType == INT_VALUE) { 181 return mIntValue != mIntDefaultValue; 182 } 183 return false; 184 } 185 write(WireBuffer buffer)186 public void write(WireBuffer buffer) { 187 buffer.writeInt(mId); 188 if (mType == FLOAT_VALUE) { 189 buffer.writeFloat(getValue()); 190 } else if (mType == INT_VALUE) { 191 buffer.writeInt(getIntValue()); 192 } 193 } 194 getObjectValue()195 public Object getObjectValue() { 196 if (mType == FLOAT_VALUE) { 197 return getValue(); 198 } 199 return getIntValue(); 200 } 201 setValue(float value)202 public void setValue(float value) { 203 mAnimatableValue = new AnimatableValue(value); 204 } 205 setValue(int value)206 public void setValue(int value) { 207 mIntValue = value; 208 } 209 } 210 211 @Override write(@onNull WireBuffer buffer)212 public void write(@NonNull WireBuffer buffer) { 213 buffer.start(OP_CODE); 214 buffer.writeInt(mValues.length); 215 for (int i = 0; i < mValues.length; i++) { 216 AttributeValue value = mValues[i]; 217 if (value.needsToWrite()) { 218 value.write(buffer); 219 } 220 } 221 } 222 223 @Override serializeToString(int indent, StringSerializer serializer)224 public void serializeToString(int indent, StringSerializer serializer) { 225 serializer.append( 226 indent, 227 "GRAPHICS_LAYER = [" 228 + mValues[SCALE_X].getValue() 229 + ", " 230 + mValues[SCALE_Y].getValue() 231 + "]"); 232 } 233 234 @NonNull 235 @Override deepToString(@onNull String indent)236 public String deepToString(@NonNull String indent) { 237 return indent + toString(); 238 } 239 240 @Override paint(@onNull PaintContext context)241 public void paint(@NonNull PaintContext context) { 242 for (int i = 0; i < mValues.length; i++) { 243 AttributeValue v = mValues[i]; 244 v.evaluate(context); 245 } 246 } 247 248 @Override toString()249 public String toString() { 250 return "GraphicsLayerModifierOperation(" 251 + mValues[SCALE_X].getValue() 252 + ", " 253 + mValues[SCALE_Y].getValue() 254 + ")"; 255 } 256 257 /** 258 * The name of the class 259 * 260 * @return the name 261 */ 262 @NonNull name()263 public static String name() { 264 return CLASS_NAME; 265 } 266 267 /** 268 * The OP_CODE for this command 269 * 270 * @return the opcode 271 */ id()272 public static int id() { 273 return OP_CODE; 274 } 275 276 /** 277 * Write the operation to the buffer 278 * 279 * @param buffer a WireBuffer 280 * @param values attributes of the layer 281 */ apply(WireBuffer buffer, HashMap<Integer, Object> values)282 public static void apply(WireBuffer buffer, HashMap<Integer, Object> values) { 283 buffer.start(OP_CODE); 284 int size = values.size(); 285 buffer.writeInt(size); 286 for (Integer key : values.keySet()) { 287 Object value = values.get(key); 288 if (value instanceof Integer) { 289 writeIntAttribute(buffer, key, (Integer) value); 290 } else if (value instanceof Float) { 291 writeFloatAttribute(buffer, key, (Float) value); 292 } 293 } 294 } 295 296 /** 297 * Utility to write an integer attribute 298 * 299 * @param buffer 300 * @param type 301 * @param value 302 */ writeIntAttribute(WireBuffer buffer, int type, int value)303 private static void writeIntAttribute(WireBuffer buffer, int type, int value) { 304 int tag = type | (DATA_TYPE_INT << 10); 305 buffer.writeInt(tag); 306 buffer.writeInt(value); 307 } 308 309 /** 310 * Utility to write a float attribute 311 * 312 * @param buffer 313 * @param type 314 * @param value 315 */ writeFloatAttribute(WireBuffer buffer, int type, float value)316 private static void writeFloatAttribute(WireBuffer buffer, int type, float value) { 317 int tag = type | (DATA_TYPE_FLOAT << 10); 318 buffer.writeInt(tag); 319 buffer.writeFloat(value); 320 } 321 322 /** 323 * Read the operation from the buffer 324 * 325 * @param buffer a WireBuffer 326 * @param operations the list of operations read so far 327 */ read(WireBuffer buffer, List<Operation> operations)328 public static void read(WireBuffer buffer, List<Operation> operations) { 329 int length = buffer.readInt(); 330 GraphicsLayerModifierOperation op = new GraphicsLayerModifierOperation(); 331 for (int i = 0; i < length; i++) { 332 op.readAttributeValue(buffer); 333 } 334 operations.add(op); 335 } 336 337 /** 338 * Read a single attribute value from the buffer 339 * 340 * @param buffer 341 */ readAttributeValue(WireBuffer buffer)342 private void readAttributeValue(WireBuffer buffer) { 343 int tag = buffer.readInt(); 344 int dataType = tag >> 10; 345 int index = (short) (tag & 0x3F); 346 if (index == BLUR_RADIUS_X || index == BLUR_RADIUS_Y) { 347 mHasBlurEffect = true; 348 mValues[HAS_BLUR].setValue(1); 349 } 350 if (dataType == DATA_TYPE_FLOAT) { 351 float value = buffer.readFloat(); 352 mValues[index].setValue(value); 353 } else if (dataType == DATA_TYPE_INT) { 354 int value = buffer.readInt(); 355 mValues[index].setValue(value); 356 } 357 } 358 359 /** 360 * Populate the documentation with a description of this operation 361 * 362 * @param doc to append the description to. 363 */ documentation(DocumentationBuilder doc)364 public static void documentation(DocumentationBuilder doc) { 365 doc.operation("Modifier Operations", OP_CODE, CLASS_NAME) 366 .description("define the GraphicsLayer Modifier"); 367 } 368 369 @Override layout(RemoteContext context, Component component, float width, float height)370 public void layout(RemoteContext context, Component component, float width, float height) {} 371 372 @Override serialize(MapSerializer serializer)373 public void serialize(MapSerializer serializer) { 374 serializer 375 .addTags(SerializeTags.MODIFIER) 376 .addType("GraphicsLayerModifierOperation") 377 .add("scaleX", mValues[SCALE_X].getValue()) 378 .add("scaleY", mValues[SCALE_Y].getValue()) 379 .add("rotationX", mValues[ROTATION_X].getValue()) 380 .add("rotationY", mValues[ROTATION_Y].getValue()) 381 .add("rotationZ", mValues[ROTATION_Z].getValue()) 382 .add("shadowElevation", mValues[SHADOW_ELEVATION].getValue()) 383 .add("transformOriginX", mValues[TRANSFORM_ORIGIN_X].getValue()) 384 .add("transformOriginY", mValues[TRANSFORM_ORIGIN_Y].getValue()) 385 .add("translationX", mValues[TRANSLATION_X].getValue()) 386 .add("translationY", mValues[TRANSLATION_Y].getValue()) 387 .add("translationZ", mValues[TRANSLATION_Z].getValue()) 388 .add("alpha", mValues[ALPHA].getValue()) 389 .add("cameraDistance", mValues[CAMERA_DISTANCE].getValue()) 390 .add("compositingStrategy", mValues[COMPOSITING_STRATEGY].getIntValue()) 391 .add("spotShadowColorId", mValues[SPOT_SHADOW_COLOR].getIntValue()) 392 .add("ambientShadowColorId", mValues[AMBIENT_SHADOW_COLOR].getIntValue()); 393 } 394 } 395