summaryrefslogtreecommitdiffstats
path: root/layout/base/MobileViewportManager.h
blob: 1d4fba1d54f785437746ebb44346f358ddf50fda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/* -*- 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/. */

#ifndef MobileViewportManager_h_
#define MobileViewportManager_h_

#include "mozilla/Logging.h"
#include "mozilla/Maybe.h"
#include "mozilla/MVMContext.h"
#include "mozilla/PresShellForwards.h"
#include "nsCOMPtr.h"
#include "nsIDOMEventListener.h"
#include "nsIObserver.h"
#include "Units.h"

class nsViewportInfo;

namespace mozilla {
class MVMContext;
namespace dom {
class Document;
class EventTarget;
}  // namespace dom
}  // namespace mozilla

class MobileViewportManager final : public nsIDOMEventListener,
                                    public nsIObserver {
 public:
  NS_DECL_ISUPPORTS
  NS_DECL_NSIDOMEVENTLISTENER
  NS_DECL_NSIOBSERVER

  /* The MobileViewportManager might be required to handle meta-viewport tags
   * and changes, or it might not (e.g. if we are in a desktop-zooming setup).
   * This enum indicates which mode the manager is in. It might make sense to
   * split these two "modes" into two separate classes but for now they have a
   * bunch of shared code and it's uncertain if that shared set will expand or
   * contract. */
  enum class ManagerType { VisualAndMetaViewport, VisualViewportOnly };

  explicit MobileViewportManager(mozilla::MVMContext* aContext,
                                 ManagerType aType);
  void Destroy();

  ManagerType GetManagerType() { return mManagerType; }

  /* Provide a resolution to use during the first paint instead of the default
   * resolution computed from the viewport info metadata. This is in the same
   * "units" as the argument to nsDOMWindowUtils::SetResolutionAndScaleTo.
   * Also takes the previous display dimensions as they were at the time the
   * resolution was stored in order to correctly adjust the resolution if the
   * device was rotated in the meantime. */
  void SetRestoreResolution(float aResolution,
                            mozilla::LayoutDeviceIntSize aDisplaySize);

  /* Compute the "intrinsic resolution", which is the smallest resolution at
   * which the layout viewport fills the visual viewport. (In typical
   * scenarios, where the aspect ratios of the two viewports match, it's the
   * resolution at which they are the same size.)
   *
   * The returned resolution is suitable for passing to
   * PresShell::SetResolutionAndScaleTo(). It's not in typed units for
   * reasons explained at the declaration of FrameMetrics::mPresShellResolution.
   */
  float ComputeIntrinsicResolution() const;

  /* The only direct calls to this should be in test code.
   * Normally, it gets called by HandleEvent().
   */
  void HandleDOMMetaAdded();

 private:
  void SetRestoreResolution(float aResolution);

 public:
  /* Notify the MobileViewportManager that a reflow is about to happen. This
   * triggers the MVM to update its internal notion of display size and CSS
   * viewport, so that code that queries those during the reflow gets an
   * up-to-date value.
   */
  void UpdateSizesBeforeReflow();

  /* Notify the MobileViewportManager that a reflow was requested in the
   * presShell.*/
  void RequestReflow(bool aForceAdjustResolution);

  /* Notify the MobileViewportManager that the resolution on the presShell was
   * updated, and the visual viewport size needs to be updated. */
  void ResolutionUpdated(mozilla::ResolutionChangeOrigin aOrigin);

  /* Called to compute the initial viewport on page load or before-first-paint,
   * whichever happens first. Also called directly if we are created after the
   * presShell is initialized. */
  void SetInitialViewport();

  const mozilla::LayoutDeviceIntSize& DisplaySize() const {
    return mDisplaySize;
  };

  /*
   * Shrink the content to fit it to the display width if no initial-scale is
   * specified and if the content is still wider than the display width.
   */
  void ShrinkToDisplaySizeIfNeeded();

  /*
   * Similar to UpdateVisualViewportSize but this should be called only when we
   * need to update visual viewport size in response to dynamic toolbar
   * transitions.
   * This function doesn't cause any reflows, just fires a visual viewport
   * resize event.
   */
  void UpdateVisualViewportSizeByDynamicToolbar(
      mozilla::ScreenIntCoord aToolbarHeight);

  nsSize GetVisualViewportSizeUpdatedByDynamicToolbar() const {
    return mVisualViewportSizeUpdatedByDynamicToolbar;
  }

  /*
   * This refreshes the visual viewport size based on the most recently
   * available information. It is intended to be called in particular after
   * the root scrollframe does a reflow, which may make scrollbars appear or
   * disappear if the content changed size.
   */
  void UpdateVisualViewportSizeForPotentialScrollbarChange();

  /*
   * Returns the composition size in CSS units when zoomed to the intrinsic
   * scale.
   */
  mozilla::CSSSize GetIntrinsicCompositionSize() const;

  mozilla::ParentLayerSize GetCompositionSizeWithoutDynamicToolbar() const;

  static mozilla::LazyLogModule gLog;

 private:
  ~MobileViewportManager();

  /* Main helper method to update the CSS viewport and any other properties that
   * need updating. */
  void RefreshViewportSize(bool aForceAdjustResolution);

  /* Secondary main helper method to update just the visual viewport size. */
  void RefreshVisualViewportSize();

  /* Helper to clamp the given zoom by the min/max in the viewport info. */
  mozilla::CSSToScreenScale ClampZoom(
      const mozilla::CSSToScreenScale& aZoom,
      const nsViewportInfo& aViewportInfo) const;

  /* Helper to update the given zoom according to changed display and viewport
   * widths. */
  mozilla::CSSToScreenScale ScaleZoomWithDisplayWidth(
      const mozilla::CSSToScreenScale& aZoom,
      const float& aDisplayWidthChangeRatio,
      const mozilla::CSSSize& aNewViewport,
      const mozilla::CSSSize& aOldViewport);

  mozilla::CSSToScreenScale ResolutionToZoom(
      const mozilla::LayoutDeviceToLayerScale& aResolution) const;
  mozilla::LayoutDeviceToLayerScale ZoomToResolution(
      const mozilla::CSSToScreenScale& aZoom) const;

  /* Updates the presShell resolution and the visual viewport size for various
   * types of changes. */
  void UpdateResolutionForFirstPaint(const mozilla::CSSSize& aViewportSize);
  void UpdateResolutionForViewportSizeChange(
      const mozilla::CSSSize& aViewportSize,
      const mozilla::Maybe<float>& aDisplayWidthChangeRatio);
  void UpdateResolutionForContentSizeChange(
      const mozilla::CSSSize& aContentSize);

  void ApplyNewZoom(const mozilla::ScreenIntSize& aDisplaySize,
                    const mozilla::CSSToScreenScale& aNewZoom);

  void UpdateVisualViewportSize(const mozilla::ScreenIntSize& aDisplaySize,
                                const mozilla::CSSToScreenScale& aZoom);

  /* Updates the displayport margins for the presShell's root scrollable frame
   */
  void UpdateDisplayPortMargins();

  /* Helper function for ComputeIntrinsicResolution(). */
  mozilla::CSSToScreenScale ComputeIntrinsicScale(
      const nsViewportInfo& aViewportInfo,
      const mozilla::ScreenIntSize& aDisplaySize,
      const mozilla::CSSSize& aViewportOrContentSize) const;

  /*
   * Returns the screen size subtracted the scrollbar sizes from |aDisplaySize|.
   */
  mozilla::ScreenIntSize GetCompositionSize(
      const mozilla::ScreenIntSize& aDisplaySize) const;

  mozilla::CSSToScreenScale GetZoom() const;

  RefPtr<mozilla::MVMContext> mContext;
  ManagerType mManagerType;
  bool mIsFirstPaint;
  bool mPainted;
  mozilla::LayoutDeviceIntSize mDisplaySize;
  mozilla::CSSSize mMobileViewportSize;
  mozilla::Maybe<float> mRestoreResolution;
  mozilla::Maybe<mozilla::ScreenIntSize> mRestoreDisplaySize;
  /*
   * The visual viewport size updated by the dynamic toolbar transitions. This
   * is typically used for the VisualViewport width/height APIs.
   * NOTE: If you want to use this value, you should make sure to flush
   * position:fixed elements layout and update
   * FrameMetrics.mFixedLayerMargins to conform with this value.
   */
  nsSize mVisualViewportSizeUpdatedByDynamicToolbar;
};

#endif