public DocumentData Parse(JsonReader reader, float scale) { string text = null; string fontName = null; double size = 0; int justification = 0; int tracking = 0; double lineHeight = 0; double baselineShift = 0; Color fillColor; Color strokeColor; double strokeWidth = 0; bool strokeOverFill = true; reader.BeginObject(); while (reader.HasNext()) { switch (reader.NextName()) { case "t": text = reader.NextString(); break; case "f": fontName = reader.NextString(); break; case "s": size = reader.NextDouble(); break; case "j": justification = reader.NextInt(); break; case "tr": tracking = reader.NextInt(); break; case "lh": lineHeight = reader.NextDouble(); break; case "ls": baselineShift = reader.NextDouble(); break; case "fc": fillColor = JsonUtils.JsonToColor(reader); break; case "sc": strokeColor = JsonUtils.JsonToColor(reader); break; case "sw": strokeWidth = reader.NextDouble(); break; case "of": strokeOverFill = reader.NextBoolean(); break; default: reader.SkipValue(); break; } } reader.EndObject(); return(new DocumentData(text, fontName, size, justification, tracking, lineHeight, baselineShift, fillColor, strokeColor, strokeWidth, strokeOverFill)); }
/// <summary> /// beginObject will already be called on the keyframe so it can be differentiated with /// a non animated value. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="composition"></param> /// <param name="reader"></param> /// <param name="scale"></param> /// <param name="valueParser"></param> /// <returns></returns> private static Keyframe <T> ParseKeyframe <T>(LottieComposition composition, JsonReader reader, float scale, IValueParser <T> valueParser) { Vector2? cp1 = null; Vector2? cp2 = null; float startFrame = 0; T startValue = default(T); T endValue = default(T); bool hold = false; IInterpolator interpolator; // Only used by PathKeyframe Vector2?pathCp1 = null; Vector2?pathCp2 = null; reader.BeginObject(); while (reader.HasNext()) { switch (reader.NextName()) { case "t": startFrame = reader.NextDouble(); break; case "s": startValue = valueParser.Parse(reader, scale); break; case "e": endValue = valueParser.Parse(reader, scale); break; case "o": cp1 = JsonUtils.JsonToPoint(reader, scale); break; case "i": cp2 = JsonUtils.JsonToPoint(reader, scale); break; case "h": hold = reader.NextInt() == 1; break; case "to": pathCp1 = JsonUtils.JsonToPoint(reader, scale); break; case "ti": pathCp2 = JsonUtils.JsonToPoint(reader, scale); break; default: reader.SkipValue(); break; } } reader.EndObject(); if (hold) { endValue = startValue; // TODO: create a HoldInterpolator so progress changes don't invalidate. interpolator = LinearInterpolator; } else if (cp1 != null && cp2 != null) { cp1 = new Vector2(MiscUtils.Clamp(cp1.Value.X, -scale, scale), MiscUtils.Clamp(cp1.Value.Y, -MaxCpValue, MaxCpValue)); cp2 = new Vector2(MiscUtils.Clamp(cp2.Value.X, -scale, scale), MiscUtils.Clamp(cp2.Value.Y, -MaxCpValue, MaxCpValue)); int hash = Utils.Utils.HashFor(cp1.Value.X, cp1.Value.Y, cp2.Value.X, cp2.Value.Y); if (GetInterpolator(hash, out var interpolatorRef) == false || interpolatorRef.TryGetTarget(out interpolator) == false) { interpolator = new PathInterpolator(cp1.Value.X / scale, cp1.Value.Y / scale, cp2.Value.X / scale, cp2.Value.Y / scale); try { PutInterpolator(hash, new WeakReference <IInterpolator>(interpolator)); } catch { // It is not clear why but SparseArrayCompat sometimes fails with this: // https://github.com/airbnb/lottie-android/issues/452 // Because this is not a critical operation, we can safely just ignore it. // I was unable to repro this to attempt a proper fix. } } } else { interpolator = LinearInterpolator; } var keyframe = new Keyframe <T>(composition, startValue, endValue, interpolator, startFrame, null) { PathCp1 = pathCp1, PathCp2 = pathCp2 }; return(keyframe); }