123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- // Copyright 2022 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ash/ambient/ui/ambient_animation_attribution_transformer.h"
- #include <string>
- #include <utility>
- #include "ash/utility/lottie_util.h"
- #include "base/check.h"
- #include "base/logging.h"
- #include "cc/paint/skottie_resource_metadata.h"
- #include "cc/paint/skottie_text_property_value.h"
- #include "cc/paint/skottie_transform_property_value.h"
- #include "cc/paint/skottie_wrapper.h"
- #include "ui/gfx/geometry/point.h"
- #include "ui/gfx/geometry/point_f.h"
- #include "ui/gfx/geometry/rect.h"
- #include "ui/gfx/geometry/rect_f.h"
- #include "ui/gfx/geometry/size.h"
- #include "ui/gfx/geometry/vector2d.h"
- #include "ui/lottie/animation.h"
- #include "ui/views/controls/animated_image_view.h"
- namespace ash {
- namespace {
- // Amount of padding there should be from the bottom-right of the
- // AnimatedImageView to the bottom-right of the attribution text box.
- constexpr gfx::Vector2d kTextBoxPaddingDip = gfx::Vector2d(24, 24);
- } // namespace
- // This translates between 2 coordinate systems. The first coordinate system
- // (the one translating from) is the views coordinate system where the origin
- // is the top-left of the view. In practice, the typical case looks like this:
- //
- // Animation
- // +-----------------------------------------------+
- // | |
- // |(0, 0) View |
- // +-----------------------------------------------|
- // | |
- // | |
- // | |
- // | |
- // | |
- // | |
- // | |
- // |-------------------------------------------+ |
- // | Attribution Text| |
- // |-------------------------------------------+ |
- // | |
- // +-----------------------------------------------+
- // | |
- // | |
- // +-----------------------------------------------+
- //
- // Note in the above, the animation's width matches the view's width, and its
- // height exceeds that of the view (the upper and lower parts of the animation
- // get cropped out). The origin is the top-left of the view, so the top-left of
- // the animation has coordinates (0, <some negative number>). The attribution
- // text box's bottom right corner has coordinates
- // (view_width - 24, view_height - 24).
- //
- // The second set of coordinates (the one translating to) is the original
- // animation's coordinate system. "Original" here refers to the
- // coordinates baked into the Lottie file. Visually, it looks the same as the
- // picture above, except:
- // * The origin is the top-left of the animation.
- // * The animation's width/height are those of the original animation (baked
- // into the Lottie file), as opposed to those of the "scaled" animation that
- // was scaled to reflect the view's bounds/dimensions.
- //
- // Note that although the typical case is illustrated above, the implementation
- // was written generically to account for all cases.
- void AmbientAnimationAttributionTransformer::TransformTextBox(
- views::AnimatedImageView& animated_image_view) {
- gfx::Transform view_to_animation_transform;
- // 1) Change the origin from the top-left of the view to the top-left of the
- // scaled animation.
- DCHECK(!animated_image_view.GetImageBounds().IsEmpty());
- gfx::Vector2d scaled_animation_origin_offset =
- animated_image_view.GetImageBounds().origin().OffsetFromOrigin();
- view_to_animation_transform.Translate(-scaled_animation_origin_offset);
- // 2) Reset the coordinates from the "scaled" animation dimensions (scaled to
- // fit the view) to the original animation dimensions baked into the Lottie
- // file.
- lottie::Animation* animation = animated_image_view.animated_image();
- DCHECK(animation);
- gfx::Size original_animation_size = animation->GetOriginalSize();
- gfx::Size scaled_animation_size = animated_image_view.GetImageBounds().size();
- view_to_animation_transform.PostScale(
- static_cast<float>(original_animation_size.width()) /
- scaled_animation_size.width(),
- static_cast<float>(original_animation_size.height()) /
- scaled_animation_size.height());
- // Apply transformation to the bottom-right corner of the text box. The
- // bottom-right corner is arbitrary here and is just used as a point of
- // reference when building the final transformed text box's coordinates.
- gfx::Rect view_bounds = animated_image_view.GetContentsBounds();
- DCHECK(!view_bounds.IsEmpty())
- << "AnimatedImageView's content bounds must be initialized before "
- "transforming the text box.";
- gfx::Point text_box_bottom_right =
- view_bounds.bottom_right() - kTextBoxPaddingDip;
- view_to_animation_transform.TransformPoint(&text_box_bottom_right);
- // In the majority of cases, the bottom-right of the text box will already be
- // within the boundaries of the original animation. There are some corner
- // cases though (ex: fitting a landscape animation file to portrait view)
- // where the bottom-right will be outside the animation's boundaries. In these
- // cases, clamp the text box's coordinates to the bottom-right of the
- // animation, or the text box will ultimately not be rendered.
- text_box_bottom_right.SetToMin(
- gfx::Rect(original_animation_size).bottom_right());
- for (const std::string& text_node_name :
- animation->skottie()->GetTextNodeNames()) {
- if (!IsCustomizableLottieId(text_node_name)) {
- DVLOG(4) << "Ignoring non-attribution text node";
- continue;
- }
- cc::SkottieResourceIdHash attribution_node_id =
- cc::HashSkottieResourceId(text_node_name);
- DCHECK(animation->text_map().contains(attribution_node_id));
- cc::SkottieTextPropertyValue& attribution_val =
- animation->text_map().at(attribution_node_id);
- // Text box's height stays the same as what's specified in the lottie file.
- gfx::RectF new_text_box = attribution_val.box();
- new_text_box.set_width(text_box_bottom_right.x());
- new_text_box.set_origin(
- gfx::PointF(0, text_box_bottom_right.y() - new_text_box.height()));
- // One final transform: The text box's coordinates must be relative to the
- // text attribution layer's "position" in the animation file (an arbitrary
- // point specified in Adobe After-Effects when the animation is built). It
- // is effectively the "local origin" for the text box, and may be different
- // for each attribution node in the animation.
- DCHECK(animation->skottie()->GetCurrentTransformPropertyValues().contains(
- attribution_node_id));
- gfx::Transform attribution_layer_shift;
- attribution_layer_shift.Translate(-animation->skottie()
- ->GetCurrentTransformPropertyValues()
- .at(attribution_node_id)
- .position.OffsetFromOrigin());
- attribution_layer_shift.TransformRect(&new_text_box);
- attribution_val.set_box(std::move(new_text_box));
- }
- }
- } // namespace ash
|