Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/gfx/layers/apz/src/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 15 kB image not shown  

Quelle  ScrollThumbUtils.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "ScrollThumbUtils.h"
#include "AsyncPanZoomController.h"
#include "FrameMetrics.h"
#include "UnitTransforms.h"
#include "Units.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/StaticPrefs_toolkit.h"

namespace mozilla {
namespace layers {
namespace apz {

struct AsyncScrollThumbTransformer {
  // Inputs
  const LayerToParentLayerMatrix4x4& mCurrentTransform;
  const gfx::Matrix4x4& mScrollableContentTransform;
  AsyncPanZoomController* mApzc;
  const FrameMetrics& mMetrics;
  const ScrollbarData& mScrollbarData;
  bool mScrollbarIsDescendant;

  // Intermediate results
  AsyncTransformComponentMatrix mAsyncTransform;
  AsyncTransformComponentMatrix mScrollbarTransform;

  LayerToParentLayerMatrix4x4 ComputeTransform();

 private:
  // Helper functions for ComputeTransform().

  // If the thumb's orientation is along |aAxis|, add transformations
  // of the thumb into |mScrollbarTransform|.
  void ApplyTransformForAxis(const Axis& aAxis);

  enum class ScrollThumbExtent { Start, End };

  // Scale the thumb by |aScale| along |aAxis|, while keeping constant the
  // position of the top denoted by |aExtent|.
  void ScaleThumbBy(const Axis& aAxis, float aScale, ScrollThumbExtent aExtent);

  // Translate the thumb along |aAxis| by |aTranslation| in "scrollbar space"
  // (CSS pixels along the scrollbar track, similar to e.g.
  // |mScrollbarData.mThumbStart|).
  void TranslateThumb(const Axis& aAxis, OuterCSSCoord aTranslation);
};

void AsyncScrollThumbTransformer::TranslateThumb(const Axis& aAxis,
                                                 OuterCSSCoord aTranslation) {
  aAxis.PostTranslate(
      mScrollbarTransform,
      ViewAs<CSSPixel>(aTranslation,
                       PixelCastJustification::CSSPixelsOfSurroundingContent) *
          mMetrics.GetDevPixelsPerCSSPixel() *
          LayoutDeviceToParentLayerScale(1.0));
}

void AsyncScrollThumbTransformer::ScaleThumbBy(const Axis& aAxis, float aScale,
                                               ScrollThumbExtent aExtent) {
  // To keep the position of the top of the thumb constant, the thumb needs to
  // translated to compensate for the scale applied. The origin with respect to
  // which the scale is applied is the origin of the layer tree, rather than
  // the origin of the scroll thumb. This means that the space between the
  // origin and the top of thumb (including the part of the scrollbar track
  // above the thumb, the part of the scrollbar above the track (i.e. a
  // scrollbar button if present), plus whatever content is above the scroll
  // frame) is scaled too, effectively translating the thumb. We undo that
  // translation here. (One can think of the adjustment being done to the
  // translation here as a change of basis. We have a method to help with that,
  // Matrix4x4::ChangeBasis(), but it wouldn't necessarily make the code cleaner
  // in this case).
  const OuterCSSCoord scrollTrackOrigin =
      aAxis.GetPointOffset(
          mMetrics.CalculateCompositionBoundsInOuterCssPixels().TopLeft()) +
      mScrollbarData.mScrollTrackStart;
  OuterCSSCoord thumbExtent = scrollTrackOrigin + mScrollbarData.mThumbStart;
  if (aExtent == ScrollThumbExtent::End) {
    thumbExtent += mScrollbarData.mThumbLength;
  }
  const OuterCSSCoord thumbExtentScaled = thumbExtent * aScale;
  const OuterCSSCoord thumbExtentDelta = thumbExtentScaled - thumbExtent;

  aAxis.PostScale(mScrollbarTransform, aScale);
  TranslateThumb(aAxis, -thumbExtentDelta);
}

void AsyncScrollThumbTransformer::ApplyTransformForAxis(const Axis& aAxis) {
  ParentLayerCoord asyncScroll = aAxis.GetTransformTranslation(mAsyncTransform);
  const float asyncZoom = aAxis.GetTransformScale(mAsyncTransform);
  const ParentLayerCoord overscroll =
      aAxis.GetPointOffset(mApzc->GetOverscrollAmount());

  bool haveAsyncZoom = !FuzzyEqualsAdditive(asyncZoom, 1.f);
  if (!haveAsyncZoom && mApzc->IsZero(asyncScroll) &&
      mApzc->IsZero(overscroll)) {
    return;
  }

  OuterCSSCoord translation;
  float scale = 1.0;

  bool recalcMode = StaticPrefs::apz_scrollthumb_recalc();
  if (recalcMode) {
    // In this branch (taken when apz.scrollthumb.recalc=true), |translation|
    // and |scale| are computed using the approach implemented in bug 1554795
    // of fully recalculating the desired position and size using the logic
    // that attempts to closely match the main-thread calculation.

    const CSSRect visualViewportRect = mApzc->GetCurrentAsyncVisualViewport(
        AsyncPanZoomController::eForCompositing);
    const CSSCoord visualViewportLength =
        aAxis.GetRectLength(visualViewportRect);

    const CSSCoord maxMinPosDifference =
        CSSCoord(
            aAxis.GetRectLength(mMetrics.GetScrollableRect()).Truncated()) -
        visualViewportLength;

    OuterCSSCoord effectiveThumbLength = mScrollbarData.mThumbLength;

    if (haveAsyncZoom) {
      // The calculations here closely follow the main thread calculations at
      // https://searchfox.org/mozilla-central/rev/0bf957f909ae1f3d19b43fd4edfc277342554836/layout/generic/nsGfxScrollFrame.cpp#6902-6927
      // and
      // https://searchfox.org/mozilla-central/rev/0bf957f909ae1f3d19b43fd4edfc277342554836/layout/xul/nsSliderFrame.cpp#587-614
      // Any modifications there should be reflected here as well.
      const CSSCoord pageIncrementMin =
          static_cast<int>(visualViewportLength * 0.8);
      CSSCoord pageIncrement;

      CSSToLayoutDeviceScale deviceScale = mMetrics.GetDevPixelsPerCSSPixel();
      if (*mScrollbarData.mDirection == ScrollDirection::eVertical) {
        const CSSCoord lineScrollAmount =
            (mApzc->GetScrollMetadata().GetLineScrollAmount() / deviceScale)
                .height;
        const double kScrollMultiplier =
            StaticPrefs::toolkit_scrollbox_verticalScrollDistance();
        CSSCoord increment = lineScrollAmount * kScrollMultiplier;

        pageIncrement =
            std::max(visualViewportLength - increment, pageIncrementMin);
      } else {
        pageIncrement = pageIncrementMin;
      }

      float ratio = pageIncrement / (maxMinPosDifference + pageIncrement);

      OuterCSSCoord desiredThumbLength{
          std::max(mScrollbarData.mThumbMinLength,
                   mScrollbarData.mScrollTrackLength * ratio)};

      // Round the thumb length to an integer number of LayoutDevice pixels, to
      // match the main-thread behaviour.
      auto outerDeviceScale = ViewAs<OuterCSSToLayoutDeviceScale>(
          deviceScale, PixelCastJustification::CSSPixelsOfSurroundingContent);
      desiredThumbLength =
          LayoutDeviceCoord((desiredThumbLength * outerDeviceScale).Rounded()) /
          outerDeviceScale;

      effectiveThumbLength = desiredThumbLength;

      scale = desiredThumbLength / mScrollbarData.mThumbLength;
    }

    // Subtracting the offset of the scrollable rect is needed for right-to-left
    // pages.
    const CSSCoord curPos = aAxis.GetRectOffset(visualViewportRect) -
                            aAxis.GetRectOffset(mMetrics.GetScrollableRect());

    const CSSToOuterCSSScale thumbPosRatio(
        (maxMinPosDifference != 0)
            ? float((mScrollbarData.mScrollTrackLength - effectiveThumbLength) /
                    maxMinPosDifference)
            : 1.f);

    const OuterCSSCoord desiredThumbPos = curPos * thumbPosRatio;

    translation = desiredThumbPos - mScrollbarData.mThumbStart;
  } else {
    // In this branch (taken when apz.scrollthumb.recalc=false), |translation|
    // and |scale| are computed using the pre-bug1554795 approach of turning
    // the async scroll and zoom deltas into transforms to apply to the
    // main-thread thumb position and size.

    // The scroll thumb needs to be scaled in the direction of scrolling by the
    // inverse of the async zoom. This is because zooming in decreases the
    // fraction of the whole srollable rect that is in view.
    scale = 1.f / asyncZoom;

    // Note: |metrics.GetZoom()| doesn't yet include the async zoom.
    CSSToParentLayerScale effectiveZoom =
        CSSToParentLayerScale(mMetrics.GetZoom().scale * asyncZoom);

    if (gfxPlatform::UseDesktopZoomingScrollbars()) {
      // As computed by GetCurrentAsyncTransform, asyncScrollY is
      //   asyncScrollY = -(GetEffectiveScrollOffset -
      //   mLastContentPaintMetrics.GetLayoutScrollOffset()) *
      //   effectiveZoom
      // where GetEffectiveScrollOffset includes the visual viewport offset that
      // the main thread knows about plus any async scrolling to the visual
      // viewport offset that the main thread does not (yet) know about. We want
      // asyncScrollY to be
      //   asyncScrollY = -(GetEffectiveScrollOffset -
      //   mLastContentPaintMetrics.GetVisualScrollOffset()) * effectiveZoom
      // because the main thread positions the scrollbars at the visual viewport
      // offset that it knows about. (aMetrics is mLastContentPaintMetrics)

      asyncScroll -= aAxis.GetPointOffset((mMetrics.GetLayoutScrollOffset() -
                                           mMetrics.GetVisualScrollOffset()) *
                                          effectiveZoom);
    }

    // Here we convert the scrollbar thumb ratio into a true unitless ratio by
    // dividing out the conversion factor from the scrollframe's parent's space
    // to the scrollframe's space.
    float unitlessThumbRatio = mScrollbarData.mThumbRatio /
                               (mMetrics.GetPresShellResolution() * asyncZoom);

    // The scroll thumb needs to be translated in opposite direction of the
    // async scroll. This is because scrolling down, which translates the layer
    // content up, should result in moving the scroll thumb down.
    ParentLayerCoord translationPL = -asyncScroll * unitlessThumbRatio;

    // The translation we computed is in the scroll frame's ParentLayer space.
    // This includes the full cumulative resolution, even if we are a subframe.
    // However, the resulting transform is used in a context where the scrollbar
    // is already subject to the resolutions of enclosing scroll frames. To
    // avoid double application of these enclosing resolutions, divide them out,
    // leaving only the local resolution if any.
    translationPL /= (mMetrics.GetCumulativeResolution().scale /
                      mMetrics.GetPresShellResolution());

    // Convert translation to CSS pixels as this is what TranslateThumb expects.
    translation = ViewAs<OuterCSSPixel>(
        translationPL / (mMetrics.GetDevPixelsPerCSSPixel() *
                         LayoutDeviceToParentLayerScale(1.0)),
        PixelCastJustification::CSSPixelsOfSurroundingContent);
  }

  // When scaling the thumb to account for the async zoom, keep the position
  // of the start of the thumb (which corresponds to the scroll offset)
  // constant.
  if (haveAsyncZoom) {
    ScaleThumbBy(aAxis, scale, ScrollThumbExtent::Start);
  }

  // If the page is overscrolled, additionally squish the thumb in accordance
  // with the overscroll amount.
  if (overscroll != 0) {
    ParentLayerCoord compBoundsLength =
        aAxis.GetRectLength(mMetrics.GetCompositionBounds());

    // It's possible for the overscroll amount to be larger than the length
    // of the composition bounds, if an overscroll animation was started with
    // a very large velocity.
    float overscrollProportion =
        std::min(std::abs(overscroll.value), compBoundsLength.value) /
        compBoundsLength.value;

    float overscrollScale = 1.0f - overscrollProportion;
    MOZ_ASSERT(overscrollScale >= 0.0f && overscrollScale <= 1.0f);
    // If we're overscrolled at the top, keep the top of the thumb in place
    // as we squish it. If we're overscrolled at the bottom, keep the bottom of
    // the thumb in place.
    ScaleThumbBy(
        aAxis, overscrollScale,
        overscroll < 0 ? ScrollThumbExtent::Start : ScrollThumbExtent::End);
  }

  TranslateThumb(aAxis, translation);
}

LayerToParentLayerMatrix4x4 AsyncScrollThumbTransformer::ComputeTransform() {
  // We only apply the transform if the scroll-target layer has non-container
  // children (i.e. when it has some possibly-visible content). This is to
  // avoid moving scroll-bars in the situation that only a scroll information
  // layer has been built for a scroll frame, as this would result in a
  // disparity between scrollbars and visible content.
  if (mMetrics.IsScrollInfoLayer()) {
    return LayerToParentLayerMatrix4x4{};
  }

  MOZ_RELEASE_ASSERT(mApzc);

  mAsyncTransform =
      mApzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing);

  // |mAsyncTransform| represents the amount by which we have scrolled and
  // zoomed since the last paint. Because the scrollbar was sized and positioned
  // based on the painted content, we need to adjust it based on asyncTransform
  // so that it reflects what the user is actually seeing now.
  if (*mScrollbarData.mDirection == ScrollDirection::eVertical) {
    ApplyTransformForAxis(mApzc->mY);
  }
  if (*mScrollbarData.mDirection == ScrollDirection::eHorizontal) {
    ApplyTransformForAxis(mApzc->mX);
  }

  LayerToParentLayerMatrix4x4 transform =
      mCurrentTransform * mScrollbarTransform;

  AsyncTransformComponentMatrix compensation;
  // If the scrollbar layer is a child of the content it is a scrollbar for,
  // then we need to adjust for any async transform (including an overscroll
  // transform) on the content. This needs to be cancelled out because layout
  // positions and sizes the scrollbar on the assumption that there is no async
  // transform, and without this adjustment the scrollbar will end up in the
  // wrong place.
  //
  // Note that since the async transform is applied on top of the content's
  // regular transform, we need to make sure to unapply the async transform in
  // the same coordinate space. This requires applying the content transform
  // and then unapplying it after unapplying the async transform.
  if (mScrollbarIsDescendant) {
    AsyncTransformComponentMatrix overscroll =
        mApzc->GetOverscrollTransform(AsyncPanZoomController::eForCompositing);
    gfx::Matrix4x4 asyncUntransform =
        (mAsyncTransform * overscroll).Inverse().ToUnknownMatrix();
    const gfx::Matrix4x4& contentTransform = mScrollableContentTransform;
    gfx::Matrix4x4 contentUntransform = contentTransform.Inverse();

    compensation *= ViewAs<AsyncTransformComponentMatrix>(
        contentTransform * asyncUntransform * contentUntransform);
  }
  transform = transform * compensation;

  return transform;
}

LayerToParentLayerMatrix4x4 ComputeTransformForScrollThumb(
    const LayerToParentLayerMatrix4x4& aCurrentTransform,
    const gfx::Matrix4x4& aScrollableContentTransform,
    AsyncPanZoomController* aApzc, const FrameMetrics& aMetrics,
    const ScrollbarData& aScrollbarData, bool aScrollbarIsDescendant) {
  return AsyncScrollThumbTransformer{
      aCurrentTransform, aScrollableContentTransform, aApzc, aMetrics,
      aScrollbarData,    aScrollbarIsDescendant}
      .ComputeTransform();
}

}  // namespace apz
}  // namespace layers
}  // namespace mozilla

Messung V0.5
C=70 H=100 G=86

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.