Add support for text range selectors (#2518)

This adds support for the [text range selector](https://lottiefiles.github.io/lottie-docs/text/#text-range-selector) type, which allows a [text style](https://lottiefiles.github.io/lottie-docs/text/#text-style) to be applied to a certain range of the text, defined by a start, end, and offset.

The text range selector implementation currently has the following limitations:
- Only text layers drawn using a Font are supported. Adding support for the glyph draw path may be possible, but I don't have a sample Lottie file.
- Only one text range is currently supported per text layer, as the parser [drops all other entries in the array](https://github.com/airbnb/lottie-android/blob/c4cb2254eca3c70199f1de5e39e3872c8c42e473/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java#L194-L196).
- Only index-based ranges are supported - percentage-based ranges are also allowed in the spec.
- Only ranges based on characters are supported. The [spec](https://lottiefiles.github.io/lottie-docs/constants/#text-based) allows characters, characters excluding spaces, words, and lines.
- Other options like easing (allows styling characters that are partially inside the range), randomize, and [shape](https://lottiefiles.github.io/lottie-docs/constants/#text-shape) of the range are not currently supported.

This also adds support for the opacity as an animatable text property which is applied multiplicatively with the transform opacity and the parent's alpha.

Partially addresses https://github.com/airbnb/lottie-android/issues/485.


https://github.com/user-attachments/assets/bcfad060-482d-48d9-a578-297c4f143ba9


https://github.com/user-attachments/assets/211dc574-5ea1-4fa3-9f78-f87ee104ce85

Co-authored-by: Allen Chen <allen.chen@airbnb.com>
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextProperties.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextProperties.java
index 1b72bb3..c67cb48 100644
--- a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextProperties.java
+++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextProperties.java
@@ -4,17 +4,13 @@
 
 public class AnimatableTextProperties {
 
-  @Nullable public final AnimatableColorValue color;
-  @Nullable public final AnimatableColorValue stroke;
-  @Nullable public final AnimatableFloatValue strokeWidth;
-  @Nullable public final AnimatableFloatValue tracking;
+  @Nullable public final AnimatableTextStyle textStyle;
+  @Nullable public final AnimatableTextRangeSelector rangeSelector;
 
-  public AnimatableTextProperties(@Nullable AnimatableColorValue color,
-      @Nullable AnimatableColorValue stroke, @Nullable AnimatableFloatValue strokeWidth,
-      @Nullable AnimatableFloatValue tracking) {
-    this.color = color;
-    this.stroke = stroke;
-    this.strokeWidth = strokeWidth;
-    this.tracking = tracking;
+  public AnimatableTextProperties(
+      @Nullable AnimatableTextStyle textStyle,
+      @Nullable AnimatableTextRangeSelector rangeSelector) {
+    this.textStyle = textStyle;
+    this.rangeSelector = rangeSelector;
   }
 }
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextRangeSelector.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextRangeSelector.java
new file mode 100644
index 0000000..413008b
--- /dev/null
+++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextRangeSelector.java
@@ -0,0 +1,25 @@
+package com.airbnb.lottie.model.animatable;
+
+import androidx.annotation.Nullable;
+import com.airbnb.lottie.model.content.TextRangeUnits;
+
+/**
+ * Defines an animated range of text that should have an [AnimatableTextProperties] applied to it.
+ */
+public class AnimatableTextRangeSelector {
+  @Nullable public final AnimatableIntegerValue start;
+  @Nullable public final AnimatableIntegerValue end;
+  @Nullable public final AnimatableIntegerValue offset;
+  public final TextRangeUnits units;
+
+  public AnimatableTextRangeSelector(
+      @Nullable AnimatableIntegerValue start,
+      @Nullable AnimatableIntegerValue end,
+      @Nullable AnimatableIntegerValue offset,
+      TextRangeUnits units) {
+    this.start = start;
+    this.end = end;
+    this.offset = offset;
+    this.units = units;
+  }
+}
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextStyle.java b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextStyle.java
new file mode 100644
index 0000000..24c3421
--- /dev/null
+++ b/lottie/src/main/java/com/airbnb/lottie/model/animatable/AnimatableTextStyle.java
@@ -0,0 +1,25 @@
+package com.airbnb.lottie.model.animatable;
+
+import androidx.annotation.Nullable;
+
+public class AnimatableTextStyle {
+
+  @Nullable public final AnimatableColorValue color;
+  @Nullable public final AnimatableColorValue stroke;
+  @Nullable public final AnimatableFloatValue strokeWidth;
+  @Nullable public final AnimatableFloatValue tracking;
+  @Nullable public final AnimatableIntegerValue opacity;
+
+  public AnimatableTextStyle(
+      @Nullable AnimatableColorValue color,
+      @Nullable AnimatableColorValue stroke,
+      @Nullable AnimatableFloatValue strokeWidth,
+      @Nullable AnimatableFloatValue tracking,
+      @Nullable AnimatableIntegerValue opacity) {
+    this.color = color;
+    this.stroke = stroke;
+    this.strokeWidth = strokeWidth;
+    this.tracking = tracking;
+    this.opacity = opacity;
+  }
+}
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/content/TextRangeUnits.java b/lottie/src/main/java/com/airbnb/lottie/model/content/TextRangeUnits.java
new file mode 100644
index 0000000..6e4f0c8
--- /dev/null
+++ b/lottie/src/main/java/com/airbnb/lottie/model/content/TextRangeUnits.java
@@ -0,0 +1,6 @@
+package com.airbnb.lottie.model.content;
+
+public enum TextRangeUnits {
+  PERCENT,
+  INDEX
+}
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/layer/TextLayer.java b/lottie/src/main/java/com/airbnb/lottie/model/layer/TextLayer.java
index 211f1d6..309950c 100644
--- a/lottie/src/main/java/com/airbnb/lottie/model/layer/TextLayer.java
+++ b/lottie/src/main/java/com/airbnb/lottie/model/layer/TextLayer.java
@@ -25,6 +25,7 @@
 import com.airbnb.lottie.model.FontCharacter;
 import com.airbnb.lottie.model.animatable.AnimatableTextProperties;
 import com.airbnb.lottie.model.content.ShapeGroup;
+import com.airbnb.lottie.model.content.TextRangeUnits;
 import com.airbnb.lottie.utils.Utils;
 import com.airbnb.lottie.value.LottieValueCallback;
 
@@ -56,6 +57,7 @@
   private final TextKeyframeAnimation textAnimation;
   private final LottieDrawable lottieDrawable;
   private final LottieComposition composition;
+  private TextRangeUnits textRangeUnits = TextRangeUnits.INDEX;
   @Nullable
   private BaseKeyframeAnimation<Integer, Integer> colorAnimation;
   @Nullable
@@ -73,9 +75,17 @@
   @Nullable
   private BaseKeyframeAnimation<Float, Float> trackingCallbackAnimation;
   @Nullable
+  private BaseKeyframeAnimation<Integer, Integer> opacityAnimation;
+  @Nullable
   private BaseKeyframeAnimation<Float, Float> textSizeCallbackAnimation;
   @Nullable
   private BaseKeyframeAnimation<Typeface, Typeface> typefaceCallbackAnimation;
+  @Nullable
+  private BaseKeyframeAnimation<Integer, Integer> textRangeStartAnimation;
+  @Nullable
+  private BaseKeyframeAnimation<Integer, Integer> textRangeEndAnimation;
+  @Nullable
+  private BaseKeyframeAnimation<Integer, Integer> textRangeOffsetAnimation;
 
   TextLayer(LottieDrawable lottieDrawable, Layer layerModel) {
     super(lottieDrawable, layerModel);
@@ -87,29 +97,57 @@
     addAnimation(textAnimation);
 
     AnimatableTextProperties textProperties = layerModel.getTextProperties();
-    if (textProperties != null && textProperties.color != null) {
-      colorAnimation = textProperties.color.createAnimation();
+    if (textProperties != null && textProperties.textStyle != null && textProperties.textStyle.color != null) {
+      colorAnimation = textProperties.textStyle.color.createAnimation();
       colorAnimation.addUpdateListener(this);
       addAnimation(colorAnimation);
     }
 
-    if (textProperties != null && textProperties.stroke != null) {
-      strokeColorAnimation = textProperties.stroke.createAnimation();
+    if (textProperties != null && textProperties.textStyle != null && textProperties.textStyle.stroke != null) {
+      strokeColorAnimation = textProperties.textStyle.stroke.createAnimation();
       strokeColorAnimation.addUpdateListener(this);
       addAnimation(strokeColorAnimation);
     }
 
-    if (textProperties != null && textProperties.strokeWidth != null) {
-      strokeWidthAnimation = textProperties.strokeWidth.createAnimation();
+    if (textProperties != null && textProperties.textStyle != null && textProperties.textStyle.strokeWidth != null) {
+      strokeWidthAnimation = textProperties.textStyle.strokeWidth.createAnimation();
       strokeWidthAnimation.addUpdateListener(this);
       addAnimation(strokeWidthAnimation);
     }
 
-    if (textProperties != null && textProperties.tracking != null) {
-      trackingAnimation = textProperties.tracking.createAnimation();
+    if (textProperties != null && textProperties.textStyle != null && textProperties.textStyle.tracking != null) {
+      trackingAnimation = textProperties.textStyle.tracking.createAnimation();
       trackingAnimation.addUpdateListener(this);
       addAnimation(trackingAnimation);
     }
+
+    if (textProperties != null && textProperties.textStyle != null && textProperties.textStyle.opacity != null) {
+      opacityAnimation = textProperties.textStyle.opacity.createAnimation();
+      opacityAnimation.addUpdateListener(this);
+      addAnimation(opacityAnimation);
+    }
+
+    if (textProperties != null && textProperties.rangeSelector != null && textProperties.rangeSelector.start != null) {
+      textRangeStartAnimation = textProperties.rangeSelector.start.createAnimation();
+      textRangeStartAnimation.addUpdateListener(this);
+      addAnimation(textRangeStartAnimation);
+    }
+
+    if (textProperties != null && textProperties.rangeSelector != null && textProperties.rangeSelector.end != null) {
+      textRangeEndAnimation = textProperties.rangeSelector.end.createAnimation();
+      textRangeEndAnimation.addUpdateListener(this);
+      addAnimation(textRangeEndAnimation);
+    }
+
+    if (textProperties != null && textProperties.rangeSelector != null && textProperties.rangeSelector.offset != null) {
+      textRangeOffsetAnimation = textProperties.rangeSelector.offset.createAnimation();
+      textRangeOffsetAnimation.addUpdateListener(this);
+      addAnimation(textRangeOffsetAnimation);
+    }
+
+    if (textProperties != null && textProperties.rangeSelector != null) {
+      textRangeUnits = textProperties.rangeSelector.units;
+    }
   }
 
   @Override
@@ -129,49 +167,86 @@
     canvas.save();
     canvas.concat(parentMatrix);
 
-    configurePaint(documentData, parentAlpha);
+    configurePaint(documentData, parentAlpha, 0);
 
     if (lottieDrawable.useTextGlyphs()) {
-      drawTextWithGlyphs(documentData, parentMatrix, font, canvas);
+      drawTextWithGlyphs(documentData, parentMatrix, font, canvas, parentAlpha);
     } else {
-      drawTextWithFont(documentData, font, canvas);
+      drawTextWithFont(documentData, font, canvas, parentAlpha);
     }
 
     canvas.restore();
   }
 
-  private void configurePaint(DocumentData documentData, int parentAlpha) {
-    if (colorCallbackAnimation != null) {
+  /**
+   * Configures the [fillPaint] and [strokePaint] used for drawing based on currently active text ranges.
+   *
+   * @param parentAlpha A value from 0 to 255 indicating the alpha of the parented layer.
+   */
+  private void configurePaint(DocumentData documentData, int parentAlpha, int indexInDocument) {
+    if (colorCallbackAnimation != null) { // dynamic property takes priority
       fillPaint.setColor(colorCallbackAnimation.getValue());
-    } else if (colorAnimation != null) {
+    } else if (colorAnimation != null && isIndexInRangeSelection(indexInDocument)) {
       fillPaint.setColor(colorAnimation.getValue());
-    } else {
+    } else { // fall back to the document color
       fillPaint.setColor(documentData.color);
     }
 
     if (strokeColorCallbackAnimation != null) {
       strokePaint.setColor(strokeColorCallbackAnimation.getValue());
-    } else if (strokeColorAnimation != null) {
+    } else if (strokeColorAnimation != null && isIndexInRangeSelection(indexInDocument)) {
       strokePaint.setColor(strokeColorAnimation.getValue());
     } else {
       strokePaint.setColor(documentData.strokeColor);
     }
-    int opacity = transform.getOpacity() == null ? 100 : transform.getOpacity().getValue();
-    int alpha = opacity * 255 / 100 * parentAlpha / 255;
+
+    // These opacity values are in the range 0 to 100
+    int transformOpacity = transform.getOpacity() == null ? 100 : transform.getOpacity().getValue();
+    int textRangeOpacity = opacityAnimation != null && isIndexInRangeSelection(indexInDocument) ? opacityAnimation.getValue() : 100;
+
+    // This alpha value needs to be in the range 0 to 255 to be applied to the Paint instances.
+    // We map the layer transform's opacity into that range and multiply it by the fractional opacity of the text range and the parent.
+    int alpha = Math.round((transformOpacity * 255f / 100f)
+        * (textRangeOpacity / 100f)
+        * parentAlpha / 255f);
     fillPaint.setAlpha(alpha);
     strokePaint.setAlpha(alpha);
 
     if (strokeWidthCallbackAnimation != null) {
       strokePaint.setStrokeWidth(strokeWidthCallbackAnimation.getValue());
-    } else if (strokeWidthAnimation != null) {
+    } else if (strokeWidthAnimation != null && isIndexInRangeSelection(indexInDocument)) {
       strokePaint.setStrokeWidth(strokeWidthAnimation.getValue());
     } else {
       strokePaint.setStrokeWidth(documentData.strokeWidth * Utils.dpScale());
     }
   }
 
+  private boolean isIndexInRangeSelection(int indexInDocument) {
+    int textLength = textAnimation.getValue().text.length();
+    if (textRangeStartAnimation != null && textRangeEndAnimation != null) {
+      // After effects supports reversed text ranges where the start index is greater than the end index.
+      // For the purposes of determining if the given index is inside of the range, we take the start as the smaller value.
+      int rangeStart = Math.min(textRangeStartAnimation.getValue(), textRangeEndAnimation.getValue());
+      int rangeEnd = Math.max(textRangeStartAnimation.getValue(), textRangeEndAnimation.getValue());
+
+      if (textRangeOffsetAnimation != null) {
+        int offset = textRangeOffsetAnimation.getValue();
+        rangeStart += offset;
+        rangeEnd += offset;
+      }
+
+      if (textRangeUnits == TextRangeUnits.INDEX) {
+        return indexInDocument >= rangeStart && indexInDocument < rangeEnd;
+      } else {
+        float currentIndexAsPercent = indexInDocument / (float) textLength * 100;
+        return currentIndexAsPercent >= rangeStart && currentIndexAsPercent < rangeEnd;
+      }
+    }
+    return true;
+  }
+
   private void drawTextWithGlyphs(
-      DocumentData documentData, Matrix parentMatrix, Font font, Canvas canvas) {
+      DocumentData documentData, Matrix parentMatrix, Font font, Canvas canvas, int parentAlpha) {
     float textSize;
     if (textSizeCallbackAnimation != null) {
       textSize = textSizeCallbackAnimation.getValue();
@@ -205,7 +280,7 @@
         canvas.save();
 
         if (offsetCanvas(canvas, documentData, lineIndex, line.width)) {
-          drawGlyphTextLine(line.text, documentData, font, canvas, parentScale, fontScale, tracking);
+          drawGlyphTextLine(line.text, documentData, font, canvas, parentScale, fontScale, tracking, parentAlpha);
         }
 
         canvas.restore();
@@ -214,7 +289,7 @@
   }
 
   private void drawGlyphTextLine(String text, DocumentData documentData,
-      Font font, Canvas canvas, float parentScale, float fontScale, float tracking) {
+      Font font, Canvas canvas, float parentScale, float fontScale, float tracking, int parentAlpha) {
     for (int i = 0; i < text.length(); i++) {
       char c = text.charAt(i);
       int characterHash = FontCharacter.hashFor(c, font.getFamily(), font.getStyle());
@@ -223,13 +298,13 @@
         // Something is wrong. Potentially, they didn't export the text as a glyph.
         continue;
       }
-      drawCharacterAsGlyph(character, fontScale, documentData, canvas);
+      drawCharacterAsGlyph(character, fontScale, documentData, canvas, i, parentAlpha);
       float tx = (float) character.getWidth() * fontScale * Utils.dpScale() + tracking;
       canvas.translate(tx, 0);
     }
   }
 
-  private void drawTextWithFont(DocumentData documentData, Font font, Canvas canvas) {
+  private void drawTextWithFont(DocumentData documentData, Font font, Canvas canvas, int parentAlpha) {
     Typeface typeface = getTypeface(font);
     if (typeface == null) {
       return;
@@ -263,6 +338,7 @@
     List<String> textLines = getTextLines(text);
     int textLineCount = textLines.size();
     int lineIndex = -1;
+    int characterIndexAtStartOfLine = 0;
     for (int i = 0; i < textLineCount; i++) {
       String textLine = textLines.get(i);
       float boxWidth = documentData.boxSize == null ? 0f : documentData.boxSize.x;
@@ -274,9 +350,11 @@
         canvas.save();
 
         if (offsetCanvas(canvas, documentData, lineIndex, line.width)) {
-          drawFontTextLine(line.text, documentData, canvas, tracking);
+          drawFontTextLine(line.text, documentData, canvas, tracking, characterIndexAtStartOfLine, parentAlpha);
         }
 
+        characterIndexAtStartOfLine += line.text.length();
+
         canvas.restore();
       }
     }
@@ -331,14 +409,23 @@
     return Arrays.asList(textLinesArray);
   }
 
-  private void drawFontTextLine(String text, DocumentData documentData, Canvas canvas, float tracking) {
+  /**
+   * @param characterIndexAtStartOfLine The index within the overall document of the character at the start of the line
+   * @param parentAlpha
+   */
+  private void drawFontTextLine(String text,
+      DocumentData documentData,
+      Canvas canvas,
+      float tracking,
+      int characterIndexAtStartOfLine,
+      int parentAlpha) {
     for (int i = 0; i < text.length(); ) {
       String charString = codePointToString(text, i);
-      i += charString.length();
-      drawCharacterFromFont(charString, documentData, canvas);
+      drawCharacterFromFont(charString, documentData, canvas, characterIndexAtStartOfLine + i, parentAlpha);
       float charWidth = fillPaint.measureText(charString);
       float tx = charWidth + tracking;
       canvas.translate(tx, 0);
+      i += charString.length();
     }
   }
 
@@ -430,7 +517,10 @@
       FontCharacter character,
       float fontScale,
       DocumentData documentData,
-      Canvas canvas) {
+      Canvas canvas,
+      int indexInDocument,
+      int parentAlpha) {
+    configurePaint(documentData, parentAlpha, indexInDocument);
     List<ContentGroup> contentGroups = getContentsForCharacter(character);
     for (int j = 0; j < contentGroups.size(); j++) {
       Path path = contentGroups.get(j).getPath();
@@ -459,7 +549,8 @@
     canvas.drawPath(path, paint);
   }
 
-  private void drawCharacterFromFont(String character, DocumentData documentData, Canvas canvas) {
+  private void drawCharacterFromFont(String character, DocumentData documentData, Canvas canvas, int indexInDocument, int parentAlpha) {
+    configurePaint(documentData, parentAlpha, indexInDocument);
     if (documentData.strokeOverFill) {
       drawCharacter(character, fillPaint, canvas);
       drawCharacter(character, strokePaint, canvas);
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/AnimatableTextPropertiesParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/AnimatableTextPropertiesParser.java
index 54a111b..c76ad86 100644
--- a/lottie/src/main/java/com/airbnb/lottie/parser/AnimatableTextPropertiesParser.java
+++ b/lottie/src/main/java/com/airbnb/lottie/parser/AnimatableTextPropertiesParser.java
@@ -1,21 +1,37 @@
 package com.airbnb.lottie.parser;
 
+import androidx.annotation.Nullable;
 import com.airbnb.lottie.LottieComposition;
 import com.airbnb.lottie.model.animatable.AnimatableColorValue;
 import com.airbnb.lottie.model.animatable.AnimatableFloatValue;
+import com.airbnb.lottie.model.animatable.AnimatableIntegerValue;
 import com.airbnb.lottie.model.animatable.AnimatableTextProperties;
+import com.airbnb.lottie.model.animatable.AnimatableTextRangeSelector;
+import com.airbnb.lottie.model.animatable.AnimatableTextStyle;
+import com.airbnb.lottie.model.content.LBlendMode;
+import com.airbnb.lottie.model.content.TextRangeUnits;
 import com.airbnb.lottie.parser.moshi.JsonReader;
+import com.airbnb.lottie.value.Keyframe;
 
 import java.io.IOException;
+import java.util.Collections;
 
 public class AnimatableTextPropertiesParser {
 
-  private static final JsonReader.Options PROPERTIES_NAMES = JsonReader.Options.of("a");
+  private static final JsonReader.Options PROPERTIES_NAMES = JsonReader.Options.of("s", "a");
+
+  private static final JsonReader.Options ANIMATABLE_RANGE_PROPERTIES_NAMES = JsonReader.Options.of(
+      "s", // start
+      "e", // end
+      "o", // offset
+      "r" // text range units (percent or index)
+  );
   private static final JsonReader.Options ANIMATABLE_PROPERTIES_NAMES = JsonReader.Options.of(
       "fc",
       "sc",
       "sw",
-      "t"
+      "t",
+      "o" // opacity
   );
 
   private AnimatableTextPropertiesParser() {
@@ -23,13 +39,17 @@
 
   public static AnimatableTextProperties parse(
       JsonReader reader, LottieComposition composition) throws IOException {
-    AnimatableTextProperties anim = null;
+    @Nullable AnimatableTextStyle textStyle = null;
+    @Nullable AnimatableTextRangeSelector rangeSelector = null;
 
     reader.beginObject();
     while (reader.hasNext()) {
       switch (reader.selectName(PROPERTIES_NAMES)) {
-        case 0:
-          anim = parseAnimatableTextProperties(reader, composition);
+        case 0: // Range selector
+          rangeSelector = parseAnimatableTextRangeSelector(reader, composition);
+          break;
+        case 1: // Text style for this range
+          textStyle = parseAnimatableTextStyle(reader, composition);
           break;
         default:
           reader.skipName();
@@ -37,19 +57,60 @@
       }
     }
     reader.endObject();
-    if (anim == null) {
-      // Not sure if this is possible.
-      return new AnimatableTextProperties(null, null, null, null);
-    }
-    return anim;
+
+    return new AnimatableTextProperties(textStyle, rangeSelector);
   }
 
-  private static AnimatableTextProperties parseAnimatableTextProperties(
+  private static AnimatableTextRangeSelector parseAnimatableTextRangeSelector(JsonReader reader, LottieComposition composition) throws IOException {
+    // TODO These may need to be floats in the future if we want to support percentage based ranges.
+    AnimatableIntegerValue start = null;
+    AnimatableIntegerValue end = null;
+    AnimatableIntegerValue offset = null;
+    TextRangeUnits units = null;
+
+    reader.beginObject();
+    while (reader.hasNext()) {
+      switch (reader.selectName(ANIMATABLE_RANGE_PROPERTIES_NAMES)) {
+        case 0: // start
+          start = AnimatableValueParser.parseInteger(reader, composition);
+          break;
+        case 1: // end
+          end = AnimatableValueParser.parseInteger(reader, composition);
+          break;
+        case 2: // offset
+          offset = AnimatableValueParser.parseInteger(reader, composition);
+          break;
+        case 3: // text range units (percent or index)
+          int textRangeUnits = reader.nextInt();
+          if (textRangeUnits != 1 && textRangeUnits != 2) {
+            composition.addWarning("Unsupported text range units: " + textRangeUnits);
+            units = TextRangeUnits.INDEX;
+            break;
+          }
+          units = textRangeUnits == 1 ? TextRangeUnits.PERCENT : TextRangeUnits.INDEX;
+          break;
+        default:
+          reader.skipName();
+          reader.skipValue();
+      }
+    }
+    reader.endObject();
+
+    // If no start value is provided, default to a non-animated value of 0 to match After Effects/Bodymovin.
+    if (start == null && end != null) {
+      start = new AnimatableIntegerValue(Collections.singletonList(new Keyframe<>(0)));
+    }
+
+    return new AnimatableTextRangeSelector(start, end, offset, units);
+  }
+
+  private static AnimatableTextStyle parseAnimatableTextStyle(
       JsonReader reader, LottieComposition composition) throws IOException {
     AnimatableColorValue color = null;
     AnimatableColorValue stroke = null;
     AnimatableFloatValue strokeWidth = null;
     AnimatableFloatValue tracking = null;
+    AnimatableIntegerValue opacity = null;
 
     reader.beginObject();
     while (reader.hasNext()) {
@@ -66,6 +127,9 @@
         case 3:
           tracking = AnimatableValueParser.parseFloat(reader, composition);
           break;
+        case 4: // opacity
+          opacity = AnimatableValueParser.parseInteger(reader, composition);
+          break;
         default:
           reader.skipName();
           reader.skipValue();
@@ -73,6 +137,6 @@
     }
     reader.endObject();
 
-    return new AnimatableTextProperties(color, stroke, strokeWidth, tracking);
+    return new AnimatableTextStyle(color, stroke, strokeWidth, tracking, opacity);
   }
 }
diff --git a/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java b/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java
index c56e213..c4ebd59 100644
--- a/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java
+++ b/lottie/src/main/java/com/airbnb/lottie/parser/LayerParser.java
@@ -179,23 +179,25 @@
           }
           reader.endArray();
           break;
-        case 12:
+        case 12: // Text data
           reader.beginObject();
           while (reader.hasNext()) {
             switch (reader.selectName(TEXT_NAMES)) {
-              case 0:
+              case 0: // "d", Text contents
                 text = AnimatableValueParser.parseDocumentData(reader, composition);
                 break;
-              case 1:
+              case 1: // "a", Text ranges with custom animations and style
                 reader.beginArray();
                 if (reader.hasNext()) {
                   textProperties = AnimatableTextPropertiesParser.parse(reader, composition);
                 }
+                // TODO support more than one text range
                 while (reader.hasNext()) {
                   reader.skipValue();
                 }
                 reader.endArray();
                 break;
+              // TODO support Text follow path and Text alignment
               default:
                 reader.skipName();
                 reader.skipValue();
diff --git a/snapshot-tests/src/main/assets/Tests/text_range_test.json b/snapshot-tests/src/main/assets/Tests/text_range_test.json
new file mode 100644
index 0000000..be0c5ca
--- /dev/null
+++ b/snapshot-tests/src/main/assets/Tests/text_range_test.json
@@ -0,0 +1,406 @@
+{
+  "v": "5.9.6",
+  "fr": 60,
+  "ip": 0,
+  "op": 327,
+  "w": 900,
+  "h": 325,
+  "nm": "Lottie Type Animation",
+  "ddd": 0,
+  "assets": [],
+  "fonts": {
+    "list": [
+      {
+        "fName": "Roboto-Regular",
+        "fFamily": "Roboto",
+        "fStyle": "Regular",
+        "ascent": 75
+      }
+    ]
+  },
+  "layers": [
+    {
+      "ddd": 0,
+      "ind": 1,
+      "ty": 5,
+      "nm": "Paris, FR",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 0,
+          "k": 100,
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            90.042,
+            220.965,
+            0
+          ],
+          "ix": 2,
+          "l": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -318.2,
+            -1.622,
+            0
+          ],
+          "ix": 1,
+          "l": 2
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            91.581,
+            91.581,
+            100
+          ],
+          "ix": 6,
+          "l": 2
+        }
+      },
+      "ao": 0,
+      "t": {
+        "d": {
+          "k": [
+            {
+              "s": {
+                "sz": [
+                  1383.20715332031,
+                  126
+                ],
+                "ps": [
+                  -328,
+                  -130
+                ],
+                "s": 140,
+                "f": "Roboto-Regular",
+                "t": "Paris, France",
+                "ca": 0,
+                "j": 0,
+                "tr": -13,
+                "lh": 168,
+                "ls": 0,
+                "fc": [
+                  0.133,
+                  0.133,
+                  0.133
+                ]
+              },
+              "t": 0
+            }
+          ]
+        },
+        "p": {},
+        "m": {
+          "g": 1,
+          "a": {
+            "a": 0,
+            "k": [
+              0,
+              0
+            ],
+            "ix": 2
+          }
+        },
+        "a": [
+          {
+            "nm": "Animator 1",
+            "s": {
+              "t": 0,
+              "xe": {
+                "a": 0,
+                "k": 0,
+                "ix": 7
+              },
+              "ne": {
+                "a": 0,
+                "k": 0,
+                "ix": 8
+              },
+              "a": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "b": 1,
+              "rn": 0,
+              "sh": 1,
+              "sm": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "s": {
+                "a": 1,
+                "k": [
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 56,
+                    "s": [
+                      13
+                    ]
+                  },
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 86,
+                    "s": [
+                      0
+                    ]
+                  },
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 116,
+                    "s": [
+                      0
+                    ]
+                  },
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        1
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0
+                      ]
+                    },
+                    "t": 146,
+                    "s": [
+                      6
+                    ]
+                  },
+                  {
+                    "i": {
+                      "x": [
+                        0
+                      ],
+                      "y": [
+                        1
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.2
+                      ],
+                      "y": [
+                        0
+                      ]
+                    },
+                    "t": 236,
+                    "s": [
+                      6
+                    ]
+                  },
+                  {
+                    "t": 296,
+                    "s": [
+                      13
+                    ]
+                  }
+                ],
+                "ix": 4
+              },
+              "e": {
+                "a": 1,
+                "k": [
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 0,
+                    "s": [
+                      0
+                    ]
+                  },
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 26,
+                    "s": [
+                      13
+                    ]
+                  },
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 176,
+                    "s": [
+                      13
+                    ]
+                  },
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        1
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0
+                      ]
+                    },
+                    "t": 206,
+                    "s": [
+                      6
+                    ]
+                  },
+                  {
+                    "i": {
+                      "x": [
+                        0
+                      ],
+                      "y": [
+                        1
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.2
+                      ],
+                      "y": [
+                        0
+                      ]
+                    },
+                    "t": 236,
+                    "s": [
+                      6
+                    ]
+                  },
+                  {
+                    "t": 296,
+                    "s": [
+                      0
+                    ]
+                  }
+                ],
+                "ix": 5
+              },
+              "r": 2
+            },
+            "a": {
+              "o": {
+                "a": 0,
+                "k": 0,
+                "ix": 9
+              }
+            }
+          }
+        ]
+      },
+      "ip": 0,
+      "op": 568,
+      "st": 0,
+      "ct": 1,
+      "bm": 0
+    }
+  ],
+  "markers": []
+}
diff --git a/snapshot-tests/src/main/assets/Tests/text_range_test_2.json b/snapshot-tests/src/main/assets/Tests/text_range_test_2.json
new file mode 100644
index 0000000..f1c16ff
--- /dev/null
+++ b/snapshot-tests/src/main/assets/Tests/text_range_test_2.json
@@ -0,0 +1,1290 @@
+{
+  "v": "5.9.6",
+  "fr": 60,
+  "ip": 0,
+  "op": 403,
+  "w": 500,
+  "h": 106,
+  "nm": "Lottie Type Animation - v2",
+  "ddd": 0,
+  "assets": [],
+  "fonts": {
+    "list": [
+      {
+        "fName": "Roboto-Regular",
+        "fFamily": "Roboto",
+        "fStyle": "Regular",
+        "ascent": 75
+      }
+    ]
+  },
+  "layers": [
+    {
+      "ddd": 0,
+      "ind": 1,
+      "ty": 5,
+      "nm": "Düsseldorf, Germany",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 330,
+              "s": [
+                0
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 342,
+              "s": [
+                100
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 392,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 402,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            34.475,
+            78.183,
+            0
+          ],
+          "ix": 2,
+          "l": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -318.2,
+            -1.622,
+            0
+          ],
+          "ix": 1,
+          "l": 2
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            32.258,
+            32.258,
+            100
+          ],
+          "ix": 6,
+          "l": 2
+        }
+      },
+      "ao": 0,
+      "t": {
+        "d": {
+          "k": [
+            {
+              "s": {
+                "sz": [
+                  1383.20715332031,
+                  126
+                ],
+                "ps": [
+                  -328,
+                  -130
+                ],
+                "s": 140,
+                "f": "Roboto-Regular",
+                "t": "Düsseldorf, Germany",
+                "ca": 0,
+                "j": 0,
+                "tr": -13,
+                "lh": 168,
+                "ls": 0,
+                "fc": [
+                  0.443,
+                  0.443,
+                  0.443
+                ]
+              },
+              "t": 0
+            }
+          ]
+        },
+        "p": {},
+        "m": {
+          "g": 1,
+          "a": {
+            "a": 0,
+            "k": [
+              0,
+              0
+            ],
+            "ix": 2
+          }
+        },
+        "a": [
+          {
+            "nm": "Animator 1",
+            "s": {
+              "t": 0,
+              "xe": {
+                "a": 0,
+                "k": 0,
+                "ix": 7
+              },
+              "ne": {
+                "a": 0,
+                "k": 0,
+                "ix": 8
+              },
+              "a": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "b": 1,
+              "rn": 0,
+              "sh": 1,
+              "sm": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "e": {
+                "a": 0,
+                "k": 3,
+                "ix": 5
+              },
+              "r": 2
+            },
+            "a": {
+              "o": {
+                "a": 0,
+                "k": 0,
+                "ix": 9
+              }
+            }
+          }
+        ]
+      },
+      "ip": 268,
+      "op": 403,
+      "st": 268,
+      "ct": 1,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 2,
+      "ty": 5,
+      "nm": "Düsseldorf, Germany",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 392,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 402,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            31.249,
+            78.183,
+            0
+          ],
+          "ix": 2,
+          "l": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -318.2,
+            -1.622,
+            0
+          ],
+          "ix": 1,
+          "l": 2
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            32.258,
+            32.258,
+            100
+          ],
+          "ix": 6,
+          "l": 2
+        }
+      },
+      "ao": 0,
+      "t": {
+        "d": {
+          "k": [
+            {
+              "s": {
+                "sz": [
+                  1383.20715332031,
+                  126
+                ],
+                "ps": [
+                  -328,
+                  -130
+                ],
+                "s": 140,
+                "f": "Roboto-Regular",
+                "t": "Düsseldorf, Germany",
+                "ca": 0,
+                "j": 0,
+                "tr": -13,
+                "lh": 168,
+                "ls": 0,
+                "fc": [
+                  0.133,
+                  0.133,
+                  0.133
+                ]
+              },
+              "t": 0
+            }
+          ]
+        },
+        "p": {},
+        "m": {
+          "g": 1,
+          "a": {
+            "a": 0,
+            "k": [
+              0,
+              0
+            ],
+            "ix": 2
+          }
+        },
+        "a": [
+          {
+            "nm": "Animator 1",
+            "s": {
+              "t": 0,
+              "xe": {
+                "a": 0,
+                "k": 0,
+                "ix": 7
+              },
+              "ne": {
+                "a": 0,
+                "k": 0,
+                "ix": 8
+              },
+              "a": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "b": 1,
+              "rn": 0,
+              "sh": 1,
+              "sm": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "s": {
+                "a": 0,
+                "k": 200,
+                "ix": 4
+              },
+              "e": {
+                "a": 1,
+                "k": [
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 297,
+                    "s": [
+                      0
+                    ]
+                  },
+                  {
+                    "t": 323,
+                    "s": [
+                      3
+                    ]
+                  }
+                ],
+                "ix": 5
+              },
+              "r": 2
+            },
+            "a": {
+              "o": {
+                "a": 0,
+                "k": 0,
+                "ix": 9
+              }
+            }
+          }
+        ]
+      },
+      "ip": 268,
+      "op": 403,
+      "st": 268,
+      "ct": 1,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 3,
+      "ty": 5,
+      "nm": "Montreal, Canada",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 196,
+              "s": [
+                0
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 208,
+              "s": [
+                100
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 258,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 268,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            34.475,
+            78.183,
+            0
+          ],
+          "ix": 2,
+          "l": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -318.2,
+            -1.622,
+            0
+          ],
+          "ix": 1,
+          "l": 2
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            32.258,
+            32.258,
+            100
+          ],
+          "ix": 6,
+          "l": 2
+        }
+      },
+      "ao": 0,
+      "t": {
+        "d": {
+          "k": [
+            {
+              "s": {
+                "sz": [
+                  1383.20715332031,
+                  126
+                ],
+                "ps": [
+                  -328,
+                  -130
+                ],
+                "s": 140,
+                "f": "Roboto-Regular",
+                "t": "Montreal, Canada",
+                "ca": 0,
+                "j": 0,
+                "tr": -13,
+                "lh": 168,
+                "ls": 0,
+                "fc": [
+                  0.443,
+                  0.443,
+                  0.443
+                ]
+              },
+              "t": 0
+            }
+          ]
+        },
+        "p": {},
+        "m": {
+          "g": 1,
+          "a": {
+            "a": 0,
+            "k": [
+              0,
+              0
+            ],
+            "ix": 2
+          }
+        },
+        "a": [
+          {
+            "nm": "Animator 1",
+            "s": {
+              "t": 0,
+              "xe": {
+                "a": 0,
+                "k": 0,
+                "ix": 7
+              },
+              "ne": {
+                "a": 0,
+                "k": 0,
+                "ix": 8
+              },
+              "a": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "b": 1,
+              "rn": 0,
+              "sh": 1,
+              "sm": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "e": {
+                "a": 0,
+                "k": 3,
+                "ix": 5
+              },
+              "r": 2
+            },
+            "a": {
+              "o": {
+                "a": 0,
+                "k": 0,
+                "ix": 9
+              }
+            }
+          }
+        ]
+      },
+      "ip": 134,
+      "op": 269,
+      "st": 134,
+      "ct": 1,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 4,
+      "ty": 5,
+      "nm": "Montreal, Canada",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 258,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 268,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            31.249,
+            78.183,
+            0
+          ],
+          "ix": 2,
+          "l": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -318.2,
+            -1.622,
+            0
+          ],
+          "ix": 1,
+          "l": 2
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            32.258,
+            32.258,
+            100
+          ],
+          "ix": 6,
+          "l": 2
+        }
+      },
+      "ao": 0,
+      "t": {
+        "d": {
+          "k": [
+            {
+              "s": {
+                "sz": [
+                  1383.20715332031,
+                  126
+                ],
+                "ps": [
+                  -328,
+                  -130
+                ],
+                "s": 140,
+                "f": "Roboto-Regular",
+                "t": "Montreal, Canada",
+                "ca": 0,
+                "j": 0,
+                "tr": -13,
+                "lh": 168,
+                "ls": 0,
+                "fc": [
+                  0.133,
+                  0.133,
+                  0.133
+                ]
+              },
+              "t": 0
+            }
+          ]
+        },
+        "p": {},
+        "m": {
+          "g": 1,
+          "a": {
+            "a": 0,
+            "k": [
+              0,
+              0
+            ],
+            "ix": 2
+          }
+        },
+        "a": [
+          {
+            "nm": "Animator 1",
+            "s": {
+              "t": 0,
+              "xe": {
+                "a": 0,
+                "k": 0,
+                "ix": 7
+              },
+              "ne": {
+                "a": 0,
+                "k": 0,
+                "ix": 8
+              },
+              "a": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "b": 1,
+              "rn": 0,
+              "sh": 1,
+              "sm": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "s": {
+                "a": 0,
+                "k": 200,
+                "ix": 4
+              },
+              "e": {
+                "a": 1,
+                "k": [
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 163,
+                    "s": [
+                      0
+                    ]
+                  },
+                  {
+                    "t": 189,
+                    "s": [
+                      3
+                    ]
+                  }
+                ],
+                "ix": 5
+              },
+              "r": 2
+            },
+            "a": {
+              "o": {
+                "a": 0,
+                "k": 0,
+                "ix": 9
+              }
+            }
+          }
+        ]
+      },
+      "ip": 134,
+      "op": 269,
+      "st": 134,
+      "ct": 1,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 5,
+      "ty": 5,
+      "nm": "Paris, France",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 62,
+              "s": [
+                0
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 74,
+              "s": [
+                100
+              ]
+            },
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 124,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 134,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            34.475,
+            78.183,
+            0
+          ],
+          "ix": 2,
+          "l": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -318.2,
+            -1.622,
+            0
+          ],
+          "ix": 1,
+          "l": 2
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            32.258,
+            32.258,
+            100
+          ],
+          "ix": 6,
+          "l": 2
+        }
+      },
+      "ao": 0,
+      "t": {
+        "d": {
+          "k": [
+            {
+              "s": {
+                "sz": [
+                  1383.20715332031,
+                  126
+                ],
+                "ps": [
+                  -328,
+                  -130
+                ],
+                "s": 140,
+                "f": "Roboto-Regular",
+                "t": "Paris, France",
+                "ca": 0,
+                "j": 0,
+                "tr": -13,
+                "lh": 168,
+                "ls": 0,
+                "fc": [
+                  0.443,
+                  0.443,
+                  0.443
+                ]
+              },
+              "t": 0
+            }
+          ]
+        },
+        "p": {},
+        "m": {
+          "g": 1,
+          "a": {
+            "a": 0,
+            "k": [
+              0,
+              0
+            ],
+            "ix": 2
+          }
+        },
+        "a": [
+          {
+            "nm": "Animator 1",
+            "s": {
+              "t": 0,
+              "xe": {
+                "a": 0,
+                "k": 0,
+                "ix": 7
+              },
+              "ne": {
+                "a": 0,
+                "k": 0,
+                "ix": 8
+              },
+              "a": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "b": 1,
+              "rn": 0,
+              "sh": 1,
+              "sm": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "e": {
+                "a": 0,
+                "k": 3,
+                "ix": 5
+              },
+              "r": 2
+            },
+            "a": {
+              "o": {
+                "a": 0,
+                "k": 0,
+                "ix": 9
+              }
+            }
+          }
+        ]
+      },
+      "ip": 0,
+      "op": 135,
+      "st": 0,
+      "ct": 1,
+      "bm": 0
+    },
+    {
+      "ddd": 0,
+      "ind": 6,
+      "ty": 5,
+      "nm": "Paris, France",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 1,
+          "k": [
+            {
+              "i": {
+                "x": [
+                  0.833
+                ],
+                "y": [
+                  0.833
+                ]
+              },
+              "o": {
+                "x": [
+                  0.167
+                ],
+                "y": [
+                  0.167
+                ]
+              },
+              "t": 124,
+              "s": [
+                100
+              ]
+            },
+            {
+              "t": 134,
+              "s": [
+                0
+              ]
+            }
+          ],
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            31.249,
+            78.183,
+            0
+          ],
+          "ix": 2,
+          "l": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            -318.2,
+            -1.622,
+            0
+          ],
+          "ix": 1,
+          "l": 2
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            32.258,
+            32.258,
+            100
+          ],
+          "ix": 6,
+          "l": 2
+        }
+      },
+      "ao": 0,
+      "t": {
+        "d": {
+          "k": [
+            {
+              "s": {
+                "sz": [
+                  1383.20715332031,
+                  126
+                ],
+                "ps": [
+                  -328,
+                  -130
+                ],
+                "s": 140,
+                "f": "Roboto-Regular",
+                "t": "Paris, France",
+                "ca": 0,
+                "j": 0,
+                "tr": -13,
+                "lh": 168,
+                "ls": 0,
+                "fc": [
+                  0.133,
+                  0.133,
+                  0.133
+                ]
+              },
+              "t": 0
+            }
+          ]
+        },
+        "p": {},
+        "m": {
+          "g": 1,
+          "a": {
+            "a": 0,
+            "k": [
+              0,
+              0
+            ],
+            "ix": 2
+          }
+        },
+        "a": [
+          {
+            "nm": "Animator 1",
+            "s": {
+              "t": 0,
+              "xe": {
+                "a": 0,
+                "k": 0,
+                "ix": 7
+              },
+              "ne": {
+                "a": 0,
+                "k": 0,
+                "ix": 8
+              },
+              "a": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "b": 1,
+              "rn": 0,
+              "sh": 1,
+              "sm": {
+                "a": 0,
+                "k": 0,
+                "ix": 6
+              },
+              "s": {
+                "a": 0,
+                "k": 200,
+                "ix": 4
+              },
+              "e": {
+                "a": 1,
+                "k": [
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 29,
+                    "s": [
+                      0
+                    ]
+                  },
+                  {
+                    "t": 55,
+                    "s": [
+                      3
+                    ]
+                  }
+                ],
+                "ix": 5
+              },
+              "r": 2
+            },
+            "a": {
+              "o": {
+                "a": 0,
+                "k": 0,
+                "ix": 9
+              }
+            }
+          }
+        ]
+      },
+      "ip": 0,
+      "op": 135,
+      "st": 0,
+      "ct": 1,
+      "bm": 0
+    }
+  ],
+  "markers": []
+}
diff --git a/snapshot-tests/src/main/assets/Tests/text_range_test_glyphs.json b/snapshot-tests/src/main/assets/Tests/text_range_test_glyphs.json
new file mode 100644
index 0000000..cdddb20
--- /dev/null
+++ b/snapshot-tests/src/main/assets/Tests/text_range_test_glyphs.json
@@ -0,0 +1,1840 @@
+{
+  "v": "5.12.2",
+  "fr": 29.9700012207031,
+  "ip": 0,
+  "op": 120.0000048877,
+  "w": 400,
+  "h": 400,
+  "nm": "Comp 1",
+  "ddd": 0,
+  "assets": [],
+  "fonts": {
+    "list": [
+      {
+        "fName": "Helvetica",
+        "fFamily": "Helvetica",
+        "fStyle": "Regular",
+        "ascent": 71.8994140625
+      }
+    ]
+  },
+  "layers": [
+    {
+      "ddd": 0,
+      "ind": 1,
+      "ty": 5,
+      "nm": "Hello World",
+      "sr": 1,
+      "ks": {
+        "o": {
+          "a": 0,
+          "k": 100,
+          "ix": 11
+        },
+        "r": {
+          "a": 0,
+          "k": 0,
+          "ix": 10
+        },
+        "p": {
+          "a": 0,
+          "k": [
+            42,
+            168,
+            0
+          ],
+          "ix": 2,
+          "l": 2
+        },
+        "a": {
+          "a": 0,
+          "k": [
+            0,
+            0,
+            0
+          ],
+          "ix": 1,
+          "l": 2
+        },
+        "s": {
+          "a": 0,
+          "k": [
+            100,
+            100,
+            100
+          ],
+          "ix": 6,
+          "l": 2
+        }
+      },
+      "ao": 0,
+      "t": {
+        "d": {
+          "k": [
+            {
+              "s": {
+                "s": 36,
+                "f": "Helvetica",
+                "t": "Hello World",
+                "ca": 0,
+                "j": 0,
+                "tr": 0,
+                "lh": 43.2000007629395,
+                "ls": 0,
+                "fc": [
+                  0.132,
+                  0.132,
+                  0.132
+                ]
+              },
+              "t": 0
+            }
+          ]
+        },
+        "p": {},
+        "m": {
+          "g": 1,
+          "a": {
+            "a": 0,
+            "k": [
+              0,
+              0
+            ],
+            "ix": 2
+          }
+        },
+        "a": [
+          {
+            "nm": "Animator 1",
+            "s": {
+              "t": 0,
+              "xe": {
+                "a": 0,
+                "k": 0,
+                "ix": 7
+              },
+              "ne": {
+                "a": 0,
+                "k": 0,
+                "ix": 8
+              },
+              "a": {
+                "a": 0,
+                "k": 100,
+                "ix": 4
+              },
+              "b": 1,
+              "rn": 0,
+              "sh": 1,
+              "sm": {
+                "a": 0,
+                "k": 100,
+                "ix": 6
+              },
+              "s": {
+                "a": 1,
+                "k": [
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 0,
+                    "s": [
+                      0
+                    ]
+                  },
+                  {
+                    "t": 119.000004846969,
+                    "s": [
+                      100
+                    ]
+                  }
+                ],
+                "ix": 1
+              },
+              "e": {
+                "a": 1,
+                "k": [
+                  {
+                    "i": {
+                      "x": [
+                        0.833
+                      ],
+                      "y": [
+                        0.833
+                      ]
+                    },
+                    "o": {
+                      "x": [
+                        0.167
+                      ],
+                      "y": [
+                        0.167
+                      ]
+                    },
+                    "t": 0,
+                    "s": [
+                      0
+                    ]
+                  },
+                  {
+                    "t": 119.000004846969,
+                    "s": [
+                      0
+                    ]
+                  }
+                ],
+                "ix": 2
+              },
+              "r": 1
+            },
+            "a": {
+              "o": {
+                "a": 0,
+                "k": 0,
+                "ix": 9
+              }
+            }
+          }
+        ]
+      },
+      "ip": 0,
+      "op": 120.0000048877,
+      "st": 0,
+      "ct": 1,
+      "bm": 0
+    }
+  ],
+  "markers": [],
+  "props": {},
+  "chars": [
+    {
+      "ch": "H",
+      "size": 36,
+      "style": "Regular",
+      "w": 72.22,
+      "data": {
+        "shapes": [
+          {
+            "ty": "gr",
+            "it": [
+              {
+                "ind": 0,
+                "ty": "sh",
+                "ix": 1,
+                "ks": {
+                  "a": 0,
+                  "k": {
+                    "i": [
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ]
+                    ],
+                    "o": [
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ]
+                    ],
+                    "v": [
+                      [
+                        7.861,
+                        0
+                      ],
+                      [
+                        17.676,
+                        0
+                      ],
+                      [
+                        17.676,
+                        -33.545
+                      ],
+                      [
+                        54.541,
+                        -33.545
+                      ],
+                      [
+                        54.541,
+                        0
+                      ],
+                      [
+                        64.355,
+                        0
+                      ],
+                      [
+                        64.355,
+                        -71.729
+                      ],
+                      [
+                        54.541,
+                        -71.729
+                      ],
+                      [
+                        54.541,
+                        -42.09
+                      ],
+                      [
+                        17.676,
+                        -42.09
+                      ],
+                      [
+                        17.676,
+                        -71.729
+                      ],
+                      [
+                        7.861,
+                        -71.729
+                      ]
+                    ],
+                    "c": true
+                  },
+                  "ix": 2
+                },
+                "nm": "H",
+                "mn": "ADBE Vector Shape - Group",
+                "hd": false
+              }
+            ],
+            "nm": "H",
+            "np": 3,
+            "cix": 2,
+            "bm": 0,
+            "ix": 1,
+            "mn": "ADBE Vector Group",
+            "hd": false
+          }
+        ]
+      },
+      "fFamily": "Helvetica"
+    },
+    {
+      "ch": "e",
+      "size": 36,
+      "style": "Regular",
+      "w": 55.62,
+      "data": {
+        "shapes": [
+          {
+            "ty": "gr",
+            "it": [
+              {
+                "ind": 0,
+                "ty": "sh",
+                "ix": 1,
+                "ks": {
+                  "a": 0,
+                  "k": {
+                    "i": [
+                      [
+                        3.688,
+                        0
+                      ],
+                      [
+                        4.529,
+                        -5.241
+                      ],
+                      [
+                        0,
+                        -8.398
+                      ],
+                      [
+                        -4.497,
+                        -4.736
+                      ],
+                      [
+                        -6.47,
+                        0
+                      ],
+                      [
+                        -2.1,
+                        0.52
+                      ],
+                      [
+                        -2.65,
+                        2.605
+                      ],
+                      [
+                        -1.286,
+                        2.361
+                      ],
+                      [
+                        -0.228,
+                        1.921
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        1.518,
+                        -1.765
+                      ],
+                      [
+                        4.554,
+                        0
+                      ],
+                      [
+                        2.325,
+                        3.215
+                      ],
+                      [
+                        0.162,
+                        5.321
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0.517,
+                        2.409
+                      ],
+                      [
+                        1.747,
+                        2.637
+                      ],
+                      [
+                        3.461,
+                        1.742
+                      ]
+                    ],
+                    "o": [
+                      [
+                        -7.312,
+                        0
+                      ],
+                      [
+                        -4.53,
+                        5.241
+                      ],
+                      [
+                        0,
+                        8.529
+                      ],
+                      [
+                        4.497,
+                        4.736
+                      ],
+                      [
+                        2.649,
+                        0
+                      ],
+                      [
+                        3.909,
+                        -0.912
+                      ],
+                      [
+                        1.582,
+                        -1.497
+                      ],
+                      [
+                        1.286,
+                        -2.36
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        -0.633,
+                        2.322
+                      ],
+                      [
+                        -2.713,
+                        3.041
+                      ],
+                      [
+                        -4.877,
+                        0
+                      ],
+                      [
+                        -2.325,
+                        -3.215
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        -5.273
+                      ],
+                      [
+                        -0.583,
+                        -3.516
+                      ],
+                      [
+                        -1.812,
+                        -2.766
+                      ],
+                      [
+                        -3.462,
+                        -1.741
+                      ]
+                    ],
+                    "v": [
+                      [
+                        28.022,
+                        -53.467
+                      ],
+                      [
+                        10.261,
+                        -45.605
+                      ],
+                      [
+                        3.467,
+                        -25.146
+                      ],
+                      [
+                        10.211,
+                        -5.249
+                      ],
+                      [
+                        26.661,
+                        1.855
+                      ],
+                      [
+                        33.784,
+                        1.074
+                      ],
+                      [
+                        43.622,
+                        -4.199
+                      ],
+                      [
+                        47.925,
+                        -9.985
+                      ],
+                      [
+                        50.195,
+                        -16.406
+                      ],
+                      [
+                        41.553,
+                        -16.406
+                      ],
+                      [
+                        38.326,
+                        -10.275
+                      ],
+                      [
+                        27.425,
+                        -5.713
+                      ],
+                      [
+                        16.621,
+                        -10.535
+                      ],
+                      [
+                        12.891,
+                        -23.34
+                      ],
+                      [
+                        50.928,
+                        -23.34
+                      ],
+                      [
+                        50.151,
+                        -34.863
+                      ],
+                      [
+                        46.657,
+                        -44.092
+                      ],
+                      [
+                        38.747,
+                        -50.854
+                      ]
+                    ],
+                    "c": true
+                  },
+                  "ix": 2
+                },
+                "nm": "e",
+                "mn": "ADBE Vector Shape - Group",
+                "hd": false
+              },
+              {
+                "ind": 1,
+                "ty": "sh",
+                "ix": 2,
+                "ks": {
+                  "a": 0,
+                  "k": {
+                    "i": [
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        -2.711,
+                        2.914
+                      ],
+                      [
+                        -4.002,
+                        0
+                      ],
+                      [
+                        -2.389,
+                        -4.231
+                      ],
+                      [
+                        -0.356,
+                        -3.809
+                      ]
+                    ],
+                    "o": [
+                      [
+                        0.161,
+                        -4.492
+                      ],
+                      [
+                        2.711,
+                        -2.913
+                      ],
+                      [
+                        5.584,
+                        0
+                      ],
+                      [
+                        1.291,
+                        2.279
+                      ],
+                      [
+                        0,
+                        0
+                      ]
+                    ],
+                    "v": [
+                      [
+                        13.086,
+                        -30.322
+                      ],
+                      [
+                        17.395,
+                        -41.431
+                      ],
+                      [
+                        27.466,
+                        -45.801
+                      ],
+                      [
+                        39.425,
+                        -39.453
+                      ],
+                      [
+                        41.895,
+                        -30.322
+                      ]
+                    ],
+                    "c": true
+                  },
+                  "ix": 2
+                },
+                "nm": "e",
+                "mn": "ADBE Vector Shape - Group",
+                "hd": false
+              }
+            ],
+            "nm": "e",
+            "np": 5,
+            "cix": 2,
+            "bm": 0,
+            "ix": 1,
+            "mn": "ADBE Vector Group",
+            "hd": false
+          }
+        ]
+      },
+      "fFamily": "Helvetica"
+    },
+    {
+      "ch": "l",
+      "size": 36,
+      "style": "Regular",
+      "w": 22.22,
+      "data": {
+        "shapes": [
+          {
+            "ty": "gr",
+            "it": [
+              {
+                "ind": 0,
+                "ty": "sh",
+                "ix": 1,
+                "ks": {
+                  "a": 0,
+                  "k": {
+                    "i": [
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ]
+                    ],
+                    "o": [
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ]
+                    ],
+                    "v": [
+                      [
+                        6.689,
+                        0
+                      ],
+                      [
+                        15.479,
+                        0
+                      ],
+                      [
+                        15.479,
+                        -71.729
+                      ],
+                      [
+                        6.689,
+                        -71.729
+                      ]
+                    ],
+                    "c": true
+                  },
+                  "ix": 2
+                },
+                "nm": "l",
+                "mn": "ADBE Vector Shape - Group",
+                "hd": false
+              }
+            ],
+            "nm": "l",
+            "np": 3,
+            "cix": 2,
+            "bm": 0,
+            "ix": 1,
+            "mn": "ADBE Vector Group",
+            "hd": false
+          }
+        ]
+      },
+      "fFamily": "Helvetica"
+    },
+    {
+      "ch": "o",
+      "size": 36,
+      "style": "Regular",
+      "w": 55.62,
+      "data": {
+        "shapes": [
+          {
+            "ty": "gr",
+            "it": [
+              {
+                "ind": 0,
+                "ty": "sh",
+                "ix": 1,
+                "ks": {
+                  "a": 0,
+                  "k": {
+                    "i": [
+                      [
+                        5.761,
+                        0
+                      ],
+                      [
+                        2.414,
+                        3.706
+                      ],
+                      [
+                        0,
+                        5.56
+                      ],
+                      [
+                        -2.414,
+                        4.097
+                      ],
+                      [
+                        -5.312,
+                        0
+                      ],
+                      [
+                        -2.446,
+                        -4.812
+                      ],
+                      [
+                        0,
+                        -4.877
+                      ],
+                      [
+                        2.141,
+                        -4.405
+                      ]
+                    ],
+                    "o": [
+                      [
+                        -5.247,
+                        0
+                      ],
+                      [
+                        -2.414,
+                        -3.706
+                      ],
+                      [
+                        0,
+                        -5.787
+                      ],
+                      [
+                        2.414,
+                        -4.097
+                      ],
+                      [
+                        5.987,
+                        0
+                      ],
+                      [
+                        1.545,
+                        3.056
+                      ],
+                      [
+                        0,
+                        5.397
+                      ],
+                      [
+                        -2.141,
+                        4.405
+                      ]
+                    ],
+                    "v": [
+                      [
+                        27.026,
+                        -5.713
+                      ],
+                      [
+                        15.535,
+                        -11.272
+                      ],
+                      [
+                        11.914,
+                        -25.172
+                      ],
+                      [
+                        15.535,
+                        -39.997
+                      ],
+                      [
+                        27.122,
+                        -46.143
+                      ],
+                      [
+                        39.772,
+                        -38.924
+                      ],
+                      [
+                        42.09,
+                        -27.025
+                      ],
+                      [
+                        38.879,
+                        -12.321
+                      ]
+                    ],
+                    "c": true
+                  },
+                  "ix": 2
+                },
+                "nm": "o",
+                "mn": "ADBE Vector Shape - Group",
+                "hd": false
+              },
+              {
+                "ind": 1,
+                "ty": "sh",
+                "ix": 2,
+                "ks": {
+                  "a": 0,
+                  "k": {
+                    "i": [
+                      [
+                        6.691,
+                        0
+                      ],
+                      [
+                        4.428,
+                        -5.203
+                      ],
+                      [
+                        0,
+                        -8.781
+                      ],
+                      [
+                        -4.202,
+                        -4.862
+                      ],
+                      [
+                        -7.144,
+                        0
+                      ],
+                      [
+                        -4.073,
+                        5.496
+                      ],
+                      [
+                        0,
+                        8.424
+                      ],
+                      [
+                        4.622,
+                        4.488
+                      ]
+                    ],
+                    "o": [
+                      [
+                        -7.467,
+                        0
+                      ],
+                      [
+                        -4.428,
+                        5.204
+                      ],
+                      [
+                        0,
+                        8.196
+                      ],
+                      [
+                        4.202,
+                        4.862
+                      ],
+                      [
+                        8.566,
+                        0
+                      ],
+                      [
+                        4.073,
+                        -5.496
+                      ],
+                      [
+                        0,
+                        -8.716
+                      ],
+                      [
+                        -4.623,
+                        -4.488
+                      ]
+                    ],
+                    "v": [
+                      [
+                        27.366,
+                        -53.809
+                      ],
+                      [
+                        9.523,
+                        -46.003
+                      ],
+                      [
+                        2.881,
+                        -25.025
+                      ],
+                      [
+                        9.184,
+                        -5.437
+                      ],
+                      [
+                        26.202,
+                        1.855
+                      ],
+                      [
+                        45.16,
+                        -6.389
+                      ],
+                      [
+                        51.27,
+                        -27.27
+                      ],
+                      [
+                        44.336,
+                        -47.076
+                      ]
+                    ],
+                    "c": true
+                  },
+                  "ix": 2
+                },
+                "nm": "o",
+                "mn": "ADBE Vector Shape - Group",
+                "hd": false
+              }
+            ],
+            "nm": "o",
+            "np": 5,
+            "cix": 2,
+            "bm": 0,
+            "ix": 1,
+            "mn": "ADBE Vector Group",
+            "hd": false
+          }
+        ]
+      },
+      "fFamily": "Helvetica"
+    },
+    {
+      "ch": " ",
+      "size": 36,
+      "style": "Regular",
+      "w": 27.78,
+      "data": {},
+      "fFamily": "Helvetica"
+    },
+    {
+      "ch": "W",
+      "size": 36,
+      "style": "Regular",
+      "w": 94.38,
+      "data": {
+        "shapes": [
+          {
+            "ty": "gr",
+            "it": [
+              {
+                "ind": 0,
+                "ty": "sh",
+                "ix": 1,
+                "ks": {
+                  "a": 0,
+                  "k": {
+                    "i": [
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ]
+                    ],
+                    "o": [
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ]
+                    ],
+                    "v": [
+                      [
+                        1.831,
+                        -71.729
+                      ],
+                      [
+                        20.581,
+                        0
+                      ],
+                      [
+                        30.786,
+                        0
+                      ],
+                      [
+                        47.437,
+                        -59.473
+                      ],
+                      [
+                        63.989,
+                        0
+                      ],
+                      [
+                        74.194,
+                        0
+                      ],
+                      [
+                        93.042,
+                        -71.729
+                      ],
+                      [
+                        82.39,
+                        -71.729
+                      ],
+                      [
+                        68.867,
+                        -13.343
+                      ],
+                      [
+                        52.617,
+                        -71.729
+                      ],
+                      [
+                        42.114,
+                        -71.729
+                      ],
+                      [
+                        25.9,
+                        -13.453
+                      ],
+                      [
+                        12.379,
+                        -71.729
+                      ]
+                    ],
+                    "c": true
+                  },
+                  "ix": 2
+                },
+                "nm": "W",
+                "mn": "ADBE Vector Shape - Group",
+                "hd": false
+              }
+            ],
+            "nm": "W",
+            "np": 3,
+            "cix": 2,
+            "bm": 0,
+            "ix": 1,
+            "mn": "ADBE Vector Group",
+            "hd": false
+          }
+        ]
+      },
+      "fFamily": "Helvetica"
+    },
+    {
+      "ch": "r",
+      "size": 36,
+      "style": "Regular",
+      "w": 33.3,
+      "data": {
+        "shapes": [
+          {
+            "ty": "gr",
+            "it": [
+              {
+                "ind": 0,
+                "ty": "sh",
+                "ix": 1,
+                "ks": {
+                  "a": 0,
+                  "k": {
+                    "i": [
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        -2.377,
+                        2.849
+                      ],
+                      [
+                        -4.427,
+                        0
+                      ],
+                      [
+                        -0.439,
+                        -0.032
+                      ],
+                      [
+                        -0.521,
+                        -0.098
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0.391,
+                        0.033
+                      ],
+                      [
+                        0.163,
+                        0
+                      ],
+                      [
+                        2.669,
+                        -2.522
+                      ],
+                      [
+                        0.684,
+                        -1.758
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ]
+                    ],
+                    "o": [
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        -3.711
+                      ],
+                      [
+                        2.376,
+                        -2.848
+                      ],
+                      [
+                        0.52,
+                        0
+                      ],
+                      [
+                        0.439,
+                        0.033
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        -0.945,
+                        -0.098
+                      ],
+                      [
+                        -0.391,
+                        -0.032
+                      ],
+                      [
+                        -3.484,
+                        0
+                      ],
+                      [
+                        -2.67,
+                        2.523
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ]
+                    ],
+                    "v": [
+                      [
+                        6.689,
+                        0
+                      ],
+                      [
+                        15.479,
+                        0
+                      ],
+                      [
+                        15.479,
+                        -30.078
+                      ],
+                      [
+                        19.043,
+                        -39.917
+                      ],
+                      [
+                        29.248,
+                        -44.189
+                      ],
+                      [
+                        30.688,
+                        -44.141
+                      ],
+                      [
+                        32.129,
+                        -43.945
+                      ],
+                      [
+                        32.129,
+                        -53.223
+                      ],
+                      [
+                        30.127,
+                        -53.418
+                      ],
+                      [
+                        29.297,
+                        -53.467
+                      ],
+                      [
+                        20.068,
+                        -49.683
+                      ],
+                      [
+                        15.039,
+                        -43.262
+                      ],
+                      [
+                        15.039,
+                        -52.295
+                      ],
+                      [
+                        6.689,
+                        -52.295
+                      ]
+                    ],
+                    "c": true
+                  },
+                  "ix": 2
+                },
+                "nm": "r",
+                "mn": "ADBE Vector Shape - Group",
+                "hd": false
+              }
+            ],
+            "nm": "r",
+            "np": 3,
+            "cix": 2,
+            "bm": 0,
+            "ix": 1,
+            "mn": "ADBE Vector Group",
+            "hd": false
+          }
+        ]
+      },
+      "fFamily": "Helvetica"
+    },
+    {
+      "ch": "d",
+      "size": 36,
+      "style": "Regular",
+      "w": 55.62,
+      "data": {
+        "shapes": [
+          {
+            "ty": "gr",
+            "it": [
+              {
+                "ind": 0,
+                "ty": "sh",
+                "ix": 1,
+                "ks": {
+                  "a": 0,
+                  "k": {
+                    "i": [
+                      [
+                        0,
+                        5.599
+                      ],
+                      [
+                        -2.737,
+                        3.386
+                      ],
+                      [
+                        -4.405,
+                        0
+                      ],
+                      [
+                        -2.689,
+                        -3.174
+                      ],
+                      [
+                        0,
+                        -6.608
+                      ],
+                      [
+                        2.607,
+                        -3.499
+                      ],
+                      [
+                        4.048,
+                        0
+                      ],
+                      [
+                        2.364,
+                        3.777
+                      ]
+                    ],
+                    "o": [
+                      [
+                        0,
+                        -6.575
+                      ],
+                      [
+                        2.737,
+                        -3.385
+                      ],
+                      [
+                        3.951,
+                        0
+                      ],
+                      [
+                        2.688,
+                        3.174
+                      ],
+                      [
+                        0,
+                        6.543
+                      ],
+                      [
+                        -2.608,
+                        3.5
+                      ],
+                      [
+                        -5.215,
+                        0
+                      ],
+                      [
+                        -2.364,
+                        -3.776
+                      ]
+                    ],
+                    "v": [
+                      [
+                        12.012,
+                        -25.537
+                      ],
+                      [
+                        16.116,
+                        -40.479
+                      ],
+                      [
+                        26.829,
+                        -45.557
+                      ],
+                      [
+                        36.788,
+                        -40.796
+                      ],
+                      [
+                        40.82,
+                        -26.123
+                      ],
+                      [
+                        36.909,
+                        -11.06
+                      ],
+                      [
+                        26.926,
+                        -5.811
+                      ],
+                      [
+                        15.558,
+                        -11.475
+                      ]
+                    ],
+                    "c": true
+                  },
+                  "ix": 2
+                },
+                "nm": "d",
+                "mn": "ADBE Vector Shape - Group",
+                "hd": false
+              },
+              {
+                "ind": 1,
+                "ty": "sh",
+                "ix": 2,
+                "ks": {
+                  "a": 0,
+                  "k": {
+                    "i": [
+                      [
+                        3.989,
+                        0
+                      ],
+                      [
+                        3.875,
+                        -5.582
+                      ],
+                      [
+                        0,
+                        -7.617
+                      ],
+                      [
+                        -4.248,
+                        -4.899
+                      ],
+                      [
+                        -5.804,
+                        0
+                      ],
+                      [
+                        -2.789,
+                        1.432
+                      ],
+                      [
+                        -2.043,
+                        3.223
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        1.556,
+                        0.977
+                      ]
+                    ],
+                    "o": [
+                      [
+                        -7.199,
+                        0
+                      ],
+                      [
+                        -3.875,
+                        5.583
+                      ],
+                      [
+                        0,
+                        8.138
+                      ],
+                      [
+                        4.248,
+                        4.9
+                      ],
+                      [
+                        3.6,
+                        0
+                      ],
+                      [
+                        2.789,
+                        -1.432
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        0,
+                        0
+                      ],
+                      [
+                        -1.978,
+                        -2.441
+                      ],
+                      [
+                        -2.692,
+                        -1.692
+                      ]
+                    ],
+                    "v": [
+                      [
+                        25.157,
+                        -53.223
+                      ],
+                      [
+                        8.546,
+                        -44.849
+                      ],
+                      [
+                        2.734,
+                        -25.049
+                      ],
+                      [
+                        9.106,
+                        -5.493
+                      ],
+                      [
+                        24.185,
+                        1.855
+                      ],
+                      [
+                        33.768,
+                        -0.293
+                      ],
+                      [
+                        41.016,
+                        -7.275
+                      ],
+                      [
+                        41.016,
+                        0
+                      ],
+                      [
+                        48.926,
+                        0
+                      ],
+                      [
+                        48.926,
+                        -71.973
+                      ],
+                      [
+                        40.479,
+                        -71.973
+                      ],
+                      [
+                        40.479,
+                        -45.557
+                      ],
+                      [
+                        35.177,
+                        -50.684
+                      ]
+                    ],
+                    "c": true
+                  },
+                  "ix": 2
+                },
+                "nm": "d",
+                "mn": "ADBE Vector Shape - Group",
+                "hd": false
+              }
+            ],
+            "nm": "d",
+            "np": 5,
+            "cix": 2,
+            "bm": 0,
+            "ix": 1,
+            "mn": "ADBE Vector Group",
+            "hd": false
+          }
+        ]
+      },
+      "fFamily": "Helvetica"
+    }
+  ]
+}