File: layout_media.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (194 lines) | stat: -rw-r--r-- 8,779 bytes parent folder | download | duplicates (4)
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
/*
 * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "third_party/blink/renderer/core/layout/layout_media.h"

#include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
#include "third_party/blink/renderer/core/html/media/media_controls.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/page.h"

namespace blink {

LayoutMedia::LayoutMedia(HTMLMediaElement* video) : LayoutImage(video) {
  SetImageResource(MakeGarbageCollected<LayoutImageResource>());
}

LayoutMedia::~LayoutMedia() = default;

void LayoutMedia::Trace(Visitor* visitor) const {
  visitor->Trace(children_);
  LayoutImage::Trace(visitor);
}

HTMLMediaElement* LayoutMedia::MediaElement() const {
  NOT_DESTROYED();
  return To<HTMLMediaElement>(GetNode());
}

bool LayoutMedia::IsChildAllowed(LayoutObject* child,
                                 const ComputedStyle& style) const {
  NOT_DESTROYED();
  // Two types of child layout objects are allowed: media controls
  // and the text track container. Filter children by node type.
  DCHECK(child->GetNode());

  // Out-of-flow positioned or floating child breaks layout hierarchy.
  // This check can be removed if ::-webkit-media-controls is made internal.
  if (style.HasOutOfFlowPosition() ||
      (style.IsFloating() && !style.IsInsideDisplayIgnoringFloatingChildren()))
    return false;

  // The user agent stylesheet (mediaControls.css) has
  // ::-webkit-media-controls { display: flex; }. If author style
  // sets display: inline we would get an inline layoutObject as a child
  // of replaced content, which is not supposed to be possible. This
  // check can be removed if ::-webkit-media-controls is made
  // internal.
  if (child->GetNode()->IsMediaControls()) {
    // LayoutObject::IsInline() doesn't work at this timing.
    DCHECK(!To<Element>(child->GetNode())
                ->GetComputedStyle()
                ->IsDisplayInlineType());
    return child->IsFlexibleBox();
  }

  if (child->GetNode()->IsTextTrackContainer() ||
      child->GetNode()->IsMediaRemotingInterstitial() ||
      child->GetNode()->IsPictureInPictureInterstitial()) {
    // LayoutObject::IsInline() doesn't work at this timing.
    DCHECK(!To<Element>(child->GetNode())
                ->GetComputedStyle()
                ->IsDisplayInlineType());
    return true;
  }

  return false;
}

void LayoutMedia::PaintReplaced(const PaintInfo&,
                                const PhysicalOffset& paint_offset) const {
  NOT_DESTROYED();
}

LayoutUnit LayoutMedia::ComputePanelWidth(
    const PhysicalRect& media_rect) const {
  NOT_DESTROYED();
  // TODO(mlamouri): we don't know if the main frame has an horizontal scrollbar
  // if it is out of process. See https://crbug.com/662480
  if (GetDocument().GetPage()->MainFrame()->IsRemoteFrame())
    return media_rect.Width();

  // TODO(foolip): when going fullscreen, the animation sometimes does not clear
  // up properly and the last `absoluteXOffset` received is incorrect. This is
  // a shortcut that we could ideally avoid. See https://crbug.com/663680
  if (MediaElement() && MediaElement()->IsFullscreen())
    return media_rect.Width();

  Page* page = GetDocument().GetPage();
  LocalFrame* main_frame = page->DeprecatedLocalMainFrame();
  LocalFrameView* page_view = main_frame ? main_frame->View() : nullptr;
  if (!main_frame || !page_view || !page_view->GetLayoutView())
    return media_rect.Width();

  // If the main frame can have a scrollbar, we'll never be cut off.
  // TODO(crbug.com/771379): Once we no longer assume that the video is in the
  // main frame for the visibility calculation below, we will only care about
  // the video's frame's scrollbar check below.
  mojom::blink::ScrollbarMode h_mode, v_mode;
  page_view->GetLayoutView()->CalculateScrollbarModes(h_mode, v_mode);
  if (h_mode != mojom::blink::ScrollbarMode::kAlwaysOff)
    return media_rect.Width();

  // If the video's frame (can be different from main frame if video is in an
  // iframe) can have a scrollbar, we'll never be cut off.
  LocalFrame* media_frame = GetFrame();
  LocalFrameView* media_page_view = media_frame ? media_frame->View() : nullptr;
  if (media_page_view && media_page_view->GetLayoutView()) {
    media_page_view->GetLayoutView()->CalculateScrollbarModes(h_mode, v_mode);
    if (h_mode != mojom::blink::ScrollbarMode::kAlwaysOff)
      return media_rect.Width();
  }

  // TODO(crbug.com/771379): This code assumes the video is in the main frame.
  // On desktop, this will include scrollbars when they stay visible.
  const LayoutUnit visible_width(page->GetVisualViewport().VisibleWidth());
  // The bottom left corner of the video.
  const gfx::PointF bottom_left_point(
      LocalToAbsolutePoint(gfx::PointF(media_rect.X(), media_rect.Bottom()),
                           kTraverseDocumentBoundaries));
  // The bottom right corner of the video.
  const gfx::PointF bottom_right_point(
      LocalToAbsolutePoint(gfx::PointF(media_rect.Right(), media_rect.Bottom()),
                           kTraverseDocumentBoundaries));

  const bool bottom_left_corner_visible = bottom_left_point.x() < visible_width;
  const bool bottom_right_corner_visible =
      bottom_right_point.x() < visible_width;

  // If both corners are visible, then we can see the whole panel.
  if (bottom_left_corner_visible && bottom_right_corner_visible)
    return media_rect.Width();

  // TODO(crbug.com/771379): Should we return zero here?
  // If neither corner is visible, use the whole length.
  if (!bottom_left_corner_visible && !bottom_right_corner_visible)
    return media_rect.Width();

  // TODO(crbug.com/771379): Right now, LayoutMedia will assume that the panel
  // will start at the bottom left corner, so if the bottom right corner is
  // showing, we'll need to set the panel width to the width of the video.
  // However, in an ideal world, if the bottom right corner is showing and the
  // bottom left corner is not, we'd shorten the panel *and* shift it towards
  // the bottom right corner (this can happen when the video has been rotated).
  if (bottom_right_corner_visible)
    return media_rect.Width();

  // One corner is within the visible viewport, while the other is outside of
  // it, so we know that the panel will cross the right edge of the page, so
  // we'll calculate the point where the panel intersects the right edge of the
  // page and then calculate the visible width of the panel from the distance
  // between the visible point and the edge intersection point.
  const float slope = (bottom_right_point.y() - bottom_left_point.y()) /
                      (bottom_right_point.x() - bottom_left_point.x());
  const float edge_intersection_y =
      bottom_left_point.y() + ((visible_width - bottom_left_point.x()) * slope);

  const gfx::PointF edge_intersection_point(visible_width, edge_intersection_y);

  // Calculate difference.
  return LayoutUnit((edge_intersection_point - bottom_left_point).Length());
}

RecalcScrollableOverflowResult LayoutMedia::RecalcScrollableOverflow() {
  NOT_DESTROYED();
  return RecalcScrollableOverflowNG();
}

}  // namespace blink