Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : /* base class of all rendering objects */
8 :
9 : #include "nsFrame.h"
10 :
11 : #include <stdarg.h>
12 : #include <algorithm>
13 :
14 : #include "gfx2DGlue.h"
15 : #include "gfxUtils.h"
16 : #include "mozilla/Attributes.h"
17 : #include "mozilla/ComputedStyle.h"
18 : #include "mozilla/DebugOnly.h"
19 : #include "mozilla/dom/ElementInlines.h"
20 : #include "mozilla/dom/Selection.h"
21 : #include "mozilla/gfx/2D.h"
22 : #include "mozilla/gfx/PathHelpers.h"
23 : #include "mozilla/Sprintf.h"
24 :
25 : #include "nsCOMPtr.h"
26 : #include "nsFlexContainerFrame.h"
27 : #include "nsFrameList.h"
28 : #include "nsPlaceholderFrame.h"
29 : #include "nsPluginFrame.h"
30 : #include "nsIBaseWindow.h"
31 : #include "nsIContent.h"
32 : #include "nsIContentInlines.h"
33 : #include "nsContentUtils.h"
34 : #include "nsCSSFrameConstructor.h"
35 : #include "nsCSSProps.h"
36 : #include "nsCSSPseudoElements.h"
37 : #include "nsCSSRendering.h"
38 : #include "nsAtom.h"
39 : #include "nsString.h"
40 : #include "nsReadableUtils.h"
41 : #include "nsTableWrapperFrame.h"
42 : #include "nsView.h"
43 : #include "nsViewManager.h"
44 : #include "nsIScrollableFrame.h"
45 : #include "nsPresContext.h"
46 : #include "nsStyleConsts.h"
47 : #include "nsIPresShell.h"
48 : #include "mozilla/Logging.h"
49 : #include "mozilla/Sprintf.h"
50 : #include "nsLayoutUtils.h"
51 : #include "LayoutLogging.h"
52 : #include "mozilla/RestyleManager.h"
53 : #include "nsInlineFrame.h"
54 : #include "nsFrameSelection.h"
55 : #include "nsGkAtoms.h"
56 : #include "nsCSSAnonBoxes.h"
57 : #include "nsCSSClipPathInstance.h"
58 :
59 : #include "nsFrameTraversal.h"
60 : #include "nsRange.h"
61 : #include "nsITextControlFrame.h"
62 : #include "nsNameSpaceManager.h"
63 : #include "nsIPercentBSizeObserver.h"
64 : #include "nsStyleStructInlines.h"
65 : #include "FrameLayerBuilder.h"
66 : #include "ImageLayers.h"
67 :
68 : #include "nsBidiPresUtils.h"
69 : #include "RubyUtils.h"
70 : #include "nsAnimationManager.h"
71 :
72 : // For triple-click pref
73 : #include "imgIContainer.h"
74 : #include "imgIRequest.h"
75 : #include "nsError.h"
76 : #include "nsContainerFrame.h"
77 : #include "nsBoxLayoutState.h"
78 : #include "nsBlockFrame.h"
79 : #include "nsDisplayList.h"
80 : #include "nsSVGIntegrationUtils.h"
81 : #include "SVGObserverUtils.h"
82 : #include "nsSVGMaskFrame.h"
83 : #include "nsChangeHint.h"
84 : #include "nsDeckFrame.h"
85 : #include "nsSubDocumentFrame.h"
86 : #include "SVGTextFrame.h"
87 : #include "RetainedDisplayListBuilder.h"
88 :
89 : #include "gfxContext.h"
90 : #include "gfxPrefs.h"
91 : #include "nsAbsoluteContainingBlock.h"
92 : #include "StickyScrollContainer.h"
93 : #include "nsFontInflationData.h"
94 : #include "nsRegion.h"
95 : #include "nsIFrameInlines.h"
96 : #include "nsStyleChangeList.h"
97 : #include "nsWindowSizes.h"
98 :
99 : #include "mozilla/AsyncEventDispatcher.h"
100 : #include "mozilla/EffectCompositor.h"
101 : #include "mozilla/EffectSet.h"
102 : #include "mozilla/EventListenerManager.h"
103 : #include "mozilla/EventStateManager.h"
104 : #include "mozilla/EventStates.h"
105 : #include "mozilla/Preferences.h"
106 : #include "mozilla/LookAndFeel.h"
107 : #include "mozilla/MouseEvents.h"
108 : #include "mozilla/ServoStyleSet.h"
109 : #include "mozilla/ServoStyleSetInlines.h"
110 : #include "mozilla/css/ImageLoader.h"
111 : #include "mozilla/gfx/Tools.h"
112 : #include "mozilla/layers/WebRenderUserData.h"
113 : #include "nsPrintfCString.h"
114 : #include "ActiveLayerTracker.h"
115 :
116 : #include "nsITheme.h"
117 : #include "nsThemeConstants.h"
118 :
119 : #include "ImageLoader.h"
120 :
121 : using namespace mozilla;
122 : using namespace mozilla::css;
123 : using namespace mozilla::dom;
124 : using namespace mozilla::gfx;
125 : using namespace mozilla::layers;
126 : using namespace mozilla::layout;
127 : typedef nsAbsoluteContainingBlock::AbsPosReflowFlags AbsPosReflowFlags;
128 :
129 : const mozilla::LayoutFrameType nsIFrame::sLayoutFrameTypes[
130 : #define FRAME_ID(...) 1 +
131 : #define ABSTRACT_FRAME_ID(...)
132 : #include "nsFrameIdList.h"
133 : #undef FRAME_ID
134 : #undef ABSTRACT_FRAME_ID
135 : 0] = {
136 : #define FRAME_ID(class_, type_, ...) mozilla::LayoutFrameType:: type_,
137 : #define ABSTRACT_FRAME_ID(...)
138 : #include "nsFrameIdList.h"
139 : #undef FRAME_ID
140 : #undef ABSTRACT_FRAME_ID
141 : };
142 :
143 : const nsIFrame::FrameClassBits nsIFrame::sFrameClassBits[
144 : #define FRAME_ID(...) 1 +
145 : #define ABSTRACT_FRAME_ID(...)
146 : #include "nsFrameIdList.h"
147 : #undef FRAME_ID
148 : #undef ABSTRACT_FRAME_ID
149 : 0] = {
150 : #define Leaf eFrameClassBitsLeaf
151 : #define NotLeaf eFrameClassBitsNone
152 : #define DynamicLeaf eFrameClassBitsDynamicLeaf
153 : #define FRAME_ID(class_, type_, leaf_, ...) leaf_,
154 : #define ABSTRACT_FRAME_ID(...)
155 : #include "nsFrameIdList.h"
156 : #undef Leaf
157 : #undef NotLeaf
158 : #undef DynamicLeaf
159 : #undef FRAME_ID
160 : #undef ABSTRACT_FRAME_ID
161 : };
162 0 :
163 : // Struct containing cached metrics for box-wrapped frames.
164 : struct nsBoxLayoutMetrics
165 : {
166 : nsSize mPrefSize;
167 : nsSize mMinSize;
168 : nsSize mMaxSize;
169 :
170 : nsSize mBlockMinSize;
171 : nsSize mBlockPrefSize;
172 : nscoord mBlockAscent;
173 :
174 : nscoord mFlex;
175 : nscoord mAscent;
176 :
177 : nsSize mLastSize;
178 : };
179 :
180 : struct nsContentAndOffset
181 : {
182 : nsIContent* mContent;
183 : int32_t mOffset;
184 : };
185 :
186 : // Some Misc #defines
187 : #define SELECTION_DEBUG 0
188 : #define FORCE_SELECTION_UPDATE 1
189 : #define CALC_DEBUG 0
190 :
191 : // This is faster than nsBidiPresUtils::IsFrameInParagraphDirection,
192 : // because it uses the frame pointer passed in without drilling down to
193 0 : // the leaf frame.
194 : static bool
195 0 : IsReversedDirectionFrame(nsIFrame* aFrame)
196 0 : {
197 : FrameBidiData bidiData = aFrame->GetBidiData();
198 : return !IS_SAME_DIRECTION(bidiData.embeddingLevel, bidiData.baseLevel);
199 : }
200 :
201 : #include "nsILineIterator.h"
202 : #include "prenv.h"
203 :
204 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(BoxMetricsProperty, nsBoxLayoutMetrics)
205 0 :
206 : static void
207 0 : InitBoxMetrics(nsIFrame* aFrame, bool aClear)
208 0 : {
209 : if (aClear) {
210 : aFrame->DeleteProperty(BoxMetricsProperty());
211 0 : }
212 0 :
213 : nsBoxLayoutMetrics* metrics = new nsBoxLayoutMetrics();
214 0 : aFrame->SetProperty(BoxMetricsProperty(), metrics);
215 0 :
216 0 : static_cast<nsFrame*>(aFrame)->nsFrame::MarkIntrinsicISizesDirty();
217 0 : metrics->mBlockAscent = 0;
218 : metrics->mLastSize.SizeTo(0, 0);
219 : }
220 0 :
221 : static bool
222 0 : IsXULBoxWrapped(const nsIFrame* aFrame)
223 0 : {
224 0 : return aFrame->GetParent() &&
225 : aFrame->GetParent()->IsXULBoxFrame() &&
226 : !aFrame->IsXULBoxFrame();
227 : }
228 0 :
229 : void
230 : nsReflowStatus::UpdateTruncated(const ReflowInput& aReflowInput,
231 0 : const ReflowOutput& aMetrics)
232 0 : {
233 : const WritingMode containerWM = aMetrics.GetWritingMode();
234 : if (aReflowInput.GetWritingMode().IsOrthogonalTo(containerWM)) {
235 0 : // Orthogonal flows are always reflowed with an unconstrained dimension,
236 0 : // so should never end up truncated (see ReflowInput::Init()).
237 0 : mTruncated = false;
238 0 : } else if (aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE &&
239 0 : aReflowInput.AvailableBSize() < aMetrics.BSize(containerWM) &&
240 : !aReflowInput.mFlags.mIsTopOfPage) {
241 0 : mTruncated = true;
242 : } else {
243 0 : mTruncated = false;
244 : }
245 : }
246 0 :
247 : /* static */ void
248 : nsIFrame::DestroyAnonymousContent(nsPresContext* aPresContext,
249 0 : already_AddRefed<nsIContent>&& aContent)
250 0 : {
251 0 : if (nsCOMPtr<nsIContent> content = aContent) {
252 : aPresContext->EventStateManager()->NativeAnonymousContentRemoved(content);
253 0 : content->UnbindFromTree();
254 : }
255 : }
256 :
257 : // Formerly the nsIFrameDebug interface
258 0 :
259 : #ifdef DEBUG
260 : std::ostream& operator<<(std::ostream& aStream,
261 0 : const nsReflowStatus& aStatus)
262 0 : {
263 : char complete = 'Y';
264 0 : if (aStatus.IsIncomplete()) {
265 0 : complete = 'N';
266 : } else if (aStatus.IsOverflowIncomplete()) {
267 : complete = 'O';
268 0 : }
269 0 :
270 : char brk = 'N';
271 0 : if (aStatus.IsInlineBreakBefore()) {
272 0 : brk = 'B';
273 : } else if (aStatus.IsInlineBreakAfter()) {
274 : brk = 'A';
275 : }
276 :
277 0 : aStream << "["
278 0 : << "Complete=" << complete << ","
279 : << "NIF=" << (aStatus.NextInFlowNeedsReflow() ? 'Y' : 'N') << ","
280 0 : << "Truncated=" << (aStatus.IsTruncated() ? 'Y' : 'N') << ","
281 0 : << "Break=" << brk << ","
282 0 : << "FirstLetter=" << (aStatus.FirstLetterComplete() ? 'Y' : 'N')
283 : << "]";
284 : return aStream;
285 : }
286 0 :
287 : nsCString
288 0 : nsReflowStatus::ToString() const
289 0 : {
290 0 : nsCString result;
291 0 : std::stringstream ss;
292 0 : ss << *this;
293 : result.Append(ss.str().c_str());
294 : return result;
295 : }
296 :
297 0 : static bool gShowFrameBorders = false;
298 :
299 0 : void nsFrame::ShowFrameBorders(bool aEnable)
300 0 : {
301 : gShowFrameBorders = aEnable;
302 0 : }
303 :
304 0 : bool nsFrame::GetShowFrameBorders()
305 : {
306 : return gShowFrameBorders;
307 : }
308 :
309 0 : static bool gShowEventTargetFrameBorder = false;
310 :
311 0 : void nsFrame::ShowEventTargetFrameBorder(bool aEnable)
312 0 : {
313 : gShowEventTargetFrameBorder = aEnable;
314 0 : }
315 :
316 0 : bool nsFrame::GetShowEventTargetFrameBorder()
317 : {
318 : return gShowEventTargetFrameBorder;
319 : }
320 :
321 : /**
322 : * Note: the log module is created during library initialization which
323 : * means that you cannot perform logging before then.
324 : */
325 : mozilla::LazyLogModule nsFrame::sFrameLogModule("frame");
326 :
327 : #endif
328 :
329 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(AbsoluteContainingBlockProperty,
330 : nsAbsoluteContainingBlock)
331 0 :
332 0 : bool
333 : nsIFrame::HasAbsolutelyPositionedChildren() const {
334 : return IsAbsoluteContainer() && GetAbsoluteContainingBlock()->HasAbsoluteFrames();
335 : }
336 0 :
337 0 : nsAbsoluteContainingBlock*
338 0 : nsIFrame::GetAbsoluteContainingBlock() const {
339 0 : NS_ASSERTION(IsAbsoluteContainer(), "The frame is not marked as an abspos container correctly");
340 0 : nsAbsoluteContainingBlock* absCB = GetProperty(AbsoluteContainingBlockProperty());
341 : NS_ASSERTION(absCB, "The frame is marked as an abspos container but doesn't have the property");
342 : return absCB;
343 : }
344 0 :
345 : void
346 0 : nsIFrame::MarkAsAbsoluteContainingBlock()
347 0 : {
348 : MOZ_ASSERT(GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
349 0 : NS_ASSERTION(!GetProperty(AbsoluteContainingBlockProperty()),
350 : "Already has an abs-pos containing block property?");
351 0 : NS_ASSERTION(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
352 0 : "Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?");
353 0 : AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
354 : SetProperty(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID()));
355 : }
356 0 :
357 : void
358 0 : nsIFrame::MarkAsNotAbsoluteContainingBlock()
359 0 : {
360 : NS_ASSERTION(!HasAbsolutelyPositionedChildren(), "Think of the children!");
361 0 : NS_ASSERTION(GetProperty(AbsoluteContainingBlockProperty()),
362 : "Should have an abs-pos containing block property");
363 0 : NS_ASSERTION(HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
364 0 : "Should have NS_FRAME_HAS_ABSPOS_CHILDREN state bit");
365 0 : MOZ_ASSERT(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN));
366 0 : RemoveStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
367 : DeleteProperty(AbsoluteContainingBlockProperty());
368 : }
369 0 :
370 : bool
371 0 : nsIFrame::CheckAndClearPaintedState()
372 0 : {
373 : bool result = (GetStateBits() & NS_FRAME_PAINTED_THEBES);
374 0 : RemoveStateBits(NS_FRAME_PAINTED_THEBES);
375 0 :
376 0 : nsIFrame::ChildListIterator lists(this);
377 0 : for (; !lists.IsDone(); lists.Next()) {
378 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
379 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
380 0 : nsIFrame* child = childFrames.get();
381 : if (child->CheckAndClearPaintedState()) {
382 : result = true;
383 : }
384 0 : }
385 : }
386 : return result;
387 : }
388 0 :
389 : bool
390 0 : nsIFrame::CheckAndClearDisplayListState()
391 0 : {
392 : bool result = BuiltDisplayList();
393 0 : SetBuiltDisplayList(false);
394 0 :
395 0 : nsIFrame::ChildListIterator lists(this);
396 0 : for (; !lists.IsDone(); lists.Next()) {
397 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
398 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
399 0 : nsIFrame* child = childFrames.get();
400 : if (child->CheckAndClearDisplayListState()) {
401 : result = true;
402 : }
403 0 : }
404 : }
405 : return result;
406 : }
407 0 :
408 : bool
409 0 : nsIFrame::IsVisibleConsideringAncestors(uint32_t aFlags) const
410 : {
411 : if (!StyleVisibility()->IsVisible()) {
412 : return false;
413 : }
414 0 :
415 0 : const nsIFrame* frame = this;
416 0 : while (frame) {
417 : nsView* view = frame->GetView();
418 : if (view && view->GetVisibility() == nsViewVisibility_kHide)
419 0 : return false;
420 0 :
421 0 : nsIFrame* parent = frame->GetParent();
422 0 : nsDeckFrame* deck = do_QueryFrame(parent);
423 : if (deck) {
424 : if (deck->GetSelectedBox() != frame)
425 : return false;
426 0 : }
427 :
428 : if (parent) {
429 0 : frame = parent;
430 0 : } else {
431 : parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
432 : if (!parent)
433 0 : break;
434 0 :
435 : if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 &&
436 : parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) {
437 : break;
438 0 : }
439 :
440 : if (!parent->StyleVisibility()->IsVisible())
441 : return false;
442 :
443 : frame = parent;
444 : }
445 : }
446 :
447 : return true;
448 : }
449 0 :
450 : void
451 : nsIFrame::FindCloserFrameForSelection(const nsPoint& aPoint,
452 0 : FrameWithDistance* aCurrentBestFrame)
453 : {
454 : if (nsLayoutUtils::PointIsCloserToRect(aPoint, mRect,
455 0 : aCurrentBestFrame->mXDistance,
456 : aCurrentBestFrame->mYDistance)) {
457 0 : aCurrentBestFrame->mFrame = this;
458 : }
459 : }
460 0 :
461 : void
462 0 : nsIFrame::ContentStatesChanged(mozilla::EventStates aStates)
463 : {
464 0 : }
465 0 :
466 : AutoWeakFrame::AutoWeakFrame(const WeakFrame& aOther)
467 0 : : mPrev(nullptr), mFrame(nullptr)
468 0 : {
469 : Init(aOther.GetFrame());
470 : }
471 0 :
472 : void
473 0 : AutoWeakFrame::Init(nsIFrame* aFrame)
474 0 : {
475 0 : Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
476 0 : mFrame = aFrame;
477 0 : if (mFrame) {
478 0 : nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
479 0 : NS_WARNING_ASSERTION(shell, "Null PresShell in AutoWeakFrame!");
480 : if (shell) {
481 0 : shell->AddAutoWeakFrame(this);
482 : } else {
483 : mFrame = nullptr;
484 0 : }
485 : }
486 : }
487 0 :
488 : void
489 0 : WeakFrame::Init(nsIFrame* aFrame)
490 0 : {
491 0 : Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
492 0 : mFrame = aFrame;
493 0 : if (mFrame) {
494 0 : nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
495 0 : MOZ_ASSERT(shell, "Null PresShell in WeakFrame!");
496 : if (shell) {
497 0 : shell->AddWeakFrame(this);
498 : } else {
499 : mFrame = nullptr;
500 0 : }
501 : }
502 : }
503 0 :
504 : nsIFrame*
505 0 : NS_NewEmptyFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
506 : {
507 : return new (aPresShell) nsFrame(aStyle);
508 0 : }
509 0 :
510 : nsFrame::nsFrame(ComputedStyle* aStyle, ClassID aID)
511 0 : : nsBox(aID)
512 : {
513 0 : MOZ_COUNT_CTOR(nsFrame);
514 0 :
515 0 : mComputedStyle = aStyle;
516 : mWritingMode = WritingMode(mComputedStyle);
517 0 : }
518 :
519 0 : nsFrame::~nsFrame()
520 : {
521 0 : MOZ_COUNT_DTOR(nsFrame);
522 :
523 0 : MOZ_ASSERT(GetVisibility() != Visibility::APPROXIMATELY_VISIBLE,
524 : "Visible nsFrame is being destroyed");
525 0 : }
526 :
527 : NS_IMPL_FRAMEARENA_HELPERS(nsFrame)
528 :
529 : // Dummy operator delete. Will never be called, but must be defined
530 0 : // to satisfy some C++ ABIs.
531 : void
532 0 : nsFrame::operator delete(void *, size_t)
533 : {
534 : MOZ_CRASH("nsFrame::operator delete should never be called");
535 0 : }
536 0 :
537 0 : NS_QUERYFRAME_HEAD(nsFrame)
538 : NS_QUERYFRAME_ENTRY(nsIFrame)
539 : NS_QUERYFRAME_TAIL_INHERITANCE_ROOT
540 :
541 : /////////////////////////////////////////////////////////////////////////////
542 : // nsIFrame
543 0 :
544 : static bool
545 : IsFontSizeInflationContainer(nsIFrame* aFrame,
546 : const nsStyleDisplay* aStyleDisplay)
547 : {
548 : /*
549 : * Font size inflation is built around the idea that we're inflating
550 : * the fonts for a pan-and-zoom UI so that when the user scales up a
551 : * block or other container to fill the width of the device, the fonts
552 : * will be readable. To do this, we need to pick what counts as a
553 : * container.
554 : *
555 : * From a code perspective, the only hard requirement is that frames
556 : * that are line participants
557 : * (nsIFrame::IsFrameOfType(nsIFrame::eLineParticipant)) are never
558 : * containers, since line layout assumes that the inflation is
559 : * consistent within a line.
560 : *
561 : * This is not an imposition, since we obviously want a bunch of text
562 : * (possibly with inline elements) flowing within a block to count the
563 : * block (or higher) as its container.
564 : *
565 : * We also want form controls, including the text in the anonymous
566 : * content inside of them, to match each other and the text next to
567 : * them, so they and their anonymous content should also not be a
568 : * container.
569 : *
570 : * However, because we can't reliably compute sizes across XUL during
571 : * reflow, any XUL frame with a XUL parent is always a container.
572 : *
573 : * There are contexts where it would be nice if some blocks didn't
574 : * count as a container, so that, for example, an indented quotation
575 : * didn't end up with a smaller font size. However, it's hard to
576 : * distinguish these situations where we really do want the indented
577 : * thing to count as a container, so we don't try, and blocks are
578 : * always containers.
579 : */
580 0 :
581 : // The root frame should always be an inflation container.
582 : if (!aFrame->GetParent()) {
583 : return true;
584 0 : }
585 0 :
586 0 : nsIContent *content = aFrame->GetContent();
587 0 : LayoutFrameType frameType = aFrame->Type();
588 0 : bool isInline = (aFrame->GetDisplay() == StyleDisplay::Inline ||
589 0 : RubyUtils::IsRubyBox(frameType) ||
590 : (aFrame->IsFloating() &&
591 : frameType == LayoutFrameType::Letter) ||
592 : // Given multiple frames for the same node, only the
593 0 : // outer one should be considered a container.
594 0 : // (Important, e.g., for nsSelectsAreaFrame.)
595 : (aFrame->GetParent()->GetContent() == content) ||
596 0 : (content && (content->IsAnyOfHTMLElements(nsGkAtoms::option,
597 0 : nsGkAtoms::optgroup,
598 0 : nsGkAtoms::select) ||
599 0 : content->IsInNativeAnonymousSubtree()))) &&
600 : !(aFrame->IsXULBoxFrame() && aFrame->GetParent()->IsXULBoxFrame());
601 : NS_ASSERTION(!aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
602 : isInline ||
603 : // br frames and mathml frames report being line
604 : // participants even when their position or display is
605 : // set
606 : aFrame->IsBrFrame() ||
607 0 : aFrame->IsFrameOfType(nsIFrame::eMathML),
608 : "line participants must not be containers");
609 0 : NS_ASSERTION(!aFrame->IsBulletFrame() || isInline,
610 : "bullets should not be containers");
611 : return !isInline;
612 : }
613 0 :
614 : void
615 : nsFrame::Init(nsIContent* aContent,
616 : nsContainerFrame* aParent,
617 0 : nsIFrame* aPrevInFlow)
618 0 : {
619 0 : MOZ_ASSERT(nsQueryFrame::FrameIID(mClass) == GetFrameId());
620 : MOZ_ASSERT(!mContent, "Double-initing a frame?");
621 : NS_ASSERTION(IsFrameOfType(eDEBUGAllFrames) &&
622 : !IsFrameOfType(eDEBUGNoFrames),
623 0 : "IsFrameOfType implementation that doesn't call base class");
624 0 :
625 0 : mContent = aContent;
626 : mParent = aParent;
627 0 : MOZ_DIAGNOSTIC_ASSERT(!mParent || PresShell() == mParent->PresShell());
628 0 :
629 : if (aPrevInFlow) {
630 : mWritingMode = aPrevInFlow->GetWritingMode();
631 0 :
632 : // Make sure the general flags bits are the same
633 : nsFrameState state = aPrevInFlow->GetStateBits();
634 0 :
635 : // Make bits that are currently off (see constructor) the same:
636 : AddStateBits(state & (NS_FRAME_INDEPENDENT_SELECTION |
637 : NS_FRAME_PART_OF_IBSPLIT |
638 : NS_FRAME_MAY_BE_TRANSFORMED |
639 0 : NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN));
640 : } else {
641 0 : PresContext()->ConstructedFrame();
642 0 : }
643 : if (GetParent()) {
644 : nsFrameState state = GetParent()->GetStateBits();
645 0 :
646 : // Make bits that are currently off (see constructor) the same:
647 : AddStateBits(state & (NS_FRAME_INDEPENDENT_SELECTION |
648 : NS_FRAME_GENERATED_CONTENT |
649 0 : NS_FRAME_IS_SVG_TEXT |
650 : NS_FRAME_IN_POPUP |
651 0 : NS_FRAME_IS_NONDISPLAY));
652 :
653 0 : if (HasAnyStateBits(NS_FRAME_IN_POPUP) && TrackingVisibility()) {
654 : // Assume all frames in popups are visible.
655 : IncApproximateVisibleCount();
656 0 : }
657 0 : }
658 0 : if (aPrevInFlow) {
659 0 : mMayHaveOpacityAnimation = aPrevInFlow->MayHaveOpacityAnimation();
660 0 : mMayHaveTransformAnimation = aPrevInFlow->MayHaveTransformAnimation();
661 0 : } else if (mContent) {
662 0 : EffectSet* effectSet = EffectSet::GetEffectSet(this);
663 0 : if (effectSet) {
664 : mMayHaveOpacityAnimation = effectSet->MayHaveOpacityAnimation();
665 : mMayHaveTransformAnimation = effectSet->MayHaveTransformAnimation();
666 : }
667 0 : }
668 0 :
669 0 : const nsStyleDisplay *disp = StyleDisplay();
670 0 : if (disp->HasTransform(this) ||
671 : (IsFrameOfType(eSupportsCSSTransforms) &&
672 : nsLayoutUtils::HasAnimationOfProperty(this, eCSSProperty_transform))) {
673 0 : // The frame gets reconstructed if we toggle the -moz-transform
674 : // property, so we can set this bit here and then ignore it.
675 0 : AddStateBits(NS_FRAME_MAY_BE_TRANSFORMED);
676 0 : }
677 0 : if (disp->mPosition == NS_STYLE_POSITION_STICKY &&
678 : !aPrevInFlow &&
679 : !(mState & NS_FRAME_IS_NONDISPLAY)) {
680 : // Note that we only add first continuations, but we really only
681 : // want to add first continuation-or-ib-split-siblings. But since we
682 : // don't yet know if we're a later part of a block-in-inline split,
683 : // we'll just add later members of a block-in-inline split here, and
684 0 : // then StickyScrollContainer will remove them later.
685 0 : StickyScrollContainer* ssc =
686 0 : StickyScrollContainer::GetStickyScrollContainerForFrame(this);
687 : if (ssc) {
688 : ssc->AddFrame(this);
689 : }
690 0 : }
691 :
692 : if (nsLayoutUtils::FontSizeInflationEnabled(PresContext()) || !GetParent()
693 : #ifdef DEBUG
694 : // We have assertions that check inflation invariants even when
695 : // font size inflation is not enabled.
696 : || true
697 0 : #endif
698 0 : ) {
699 0 : if (IsFontSizeInflationContainer(this, disp)) {
700 : AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER);
701 0 : if (!GetParent() ||
702 0 : // I'd use NS_FRAME_OUT_OF_FLOW, but it's not set yet.
703 : disp->IsFloating(this) || disp->IsAbsolutelyPositioned(this)) {
704 : AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
705 0 : }
706 : }
707 : NS_ASSERTION(GetParent() ||
708 : (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER),
709 : "root frame should always be a container");
710 0 : }
711 0 :
712 : if (PresShell()->AssumeAllFramesVisible() && TrackingVisibility()) {
713 : IncApproximateVisibleCount();
714 0 : }
715 :
716 0 : DidSetComputedStyle(nullptr);
717 0 :
718 : if (::IsXULBoxWrapped(this))
719 : ::InitBoxMetrics(this, false);
720 :
721 : // For a newly created frame, we need to update this frame's visibility state.
722 : // Usually we update the state when the frame is restyled and has a
723 0 : // VisibilityChange change hint but we don't generate any change hints for
724 0 : // newly created frames.
725 : UpdateVisibleDescendantsState();
726 : }
727 0 :
728 : void
729 0 : nsFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData)
730 : {
731 0 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
732 : "destroy called on frame while scripts not blocked");
733 0 : NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(),
734 0 : "Frames should be removed before destruction.");
735 0 : NS_ASSERTION(aDestructRoot, "Must specify destruct root");
736 : MOZ_ASSERT(!HasAbsolutelyPositionedChildren());
737 : MOZ_ASSERT(!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT),
738 0 : "NS_FRAME_PART_OF_IBSPLIT set on non-nsContainerFrame?");
739 :
740 0 : SVGObserverUtils::InvalidateDirectRenderingObservers(this);
741 :
742 0 : if (StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) {
743 0 : StickyScrollContainer* ssc =
744 0 : StickyScrollContainer::GetStickyScrollContainerForFrame(this);
745 : if (ssc) {
746 : ssc->RemoveFrame(this);
747 : }
748 0 : }
749 0 :
750 0 : nsPresContext* presContext = PresContext();
751 0 : nsIPresShell* shell = presContext->GetPresShell();
752 0 : if (mState & NS_FRAME_OUT_OF_FLOW) {
753 : nsPlaceholderFrame* placeholder = GetPlaceholderFrame();
754 0 : NS_ASSERTION(!placeholder || (aDestructRoot != this),
755 : "Don't call Destroy() on OOFs, call Destroy() on the placeholder.");
756 : NS_ASSERTION(!placeholder ||
757 : nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, placeholder),
758 0 : "Placeholder relationship should have been torn down already; "
759 0 : "this might mean we have a stray placeholder in the tree.");
760 : if (placeholder) {
761 : placeholder->SetOutOfFlowFrame(nullptr);
762 : }
763 0 : }
764 :
765 0 : if (IsPrimaryFrame()) {
766 : // This needs to happen before we clear our Properties() table.
767 : ActiveLayerTracker::TransferActivityToContent(this, mContent);
768 0 : }
769 0 :
770 : if (HasCSSAnimations() || HasCSSTransitions() ||
771 : EffectSet::GetEffectSet(this)) {
772 : // If no new frame for this element is created by the end of the
773 0 : // restyling process, stop animations and transitions for this frame
774 : RestyleManager::AnimationsWithDestroyedFrame* adf =
775 0 : presContext->RestyleManager()->GetAnimationsWithDestroyedFrame();
776 0 : // AnimationsWithDestroyedFrame only lives during the restyling process.
777 : if (adf) {
778 : adf->Put(mContent, mComputedStyle);
779 : }
780 : }
781 :
782 : // Disable visibility tracking. Note that we have to do this before we clear
783 : // frame properties and lose track of whether we were previously visible.
784 : // XXX(seth): It'd be ideal to assert that we're already marked nonvisible
785 0 : // here, but it's unfortunately tricky to guarantee in the face of things like
786 : // frame reconstruction induced by style changes.
787 : DisableVisibilityTracking();
788 0 :
789 : // Ensure that we're not in the approximately visible list anymore.
790 0 : PresContext()->GetPresShell()->RemoveFrameFromApproximatelyVisibleList(this);
791 :
792 0 : shell->NotifyDestroyingFrame(this);
793 0 :
794 : if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
795 : shell->ClearFrameRefs(this);
796 0 : }
797 0 :
798 0 : nsView* view = GetView();
799 0 : if (view) {
800 : view->SetFrame(nullptr);
801 : view->Destroy();
802 : }
803 0 :
804 0 : // Make sure that our deleted frame can't be returned from GetPrimaryFrame()
805 : if (IsPrimaryFrame()) {
806 : mContent->SetPrimaryFrame(nullptr);
807 :
808 0 : // Pass the root of a generated content subtree (e.g. ::after/::before) to
809 0 : // aPostDestroyData to unbind it after frame destruction is done.
810 0 : if (HasAnyStateBits(NS_FRAME_GENERATED_CONTENT) &&
811 : mContent->IsRootOfNativeAnonymousSubtree()) {
812 : aPostDestroyData.AddGeneratedContent(mContent.forget());
813 : }
814 : }
815 :
816 0 : // Delete all properties attached to the frame, to ensure any property
817 : // destructors that need the frame pointer are handled properly.
818 : DeleteAllProperties();
819 :
820 : // Must retrieve the object ID before calling destructors, so the
821 : // vtable is still valid.
822 : //
823 : // Note to future tweakers: having the method that returns the
824 : // object size call the destructor will not avoid an indirect call;
825 : // the compiler cannot devirtualize the call to the destructor even
826 0 : // if it's from a method defined in the same class.
827 0 :
828 : nsQueryFrame::FrameIID id = GetFrameId();
829 : this->~nsFrame();
830 :
831 0 : #ifdef DEBUG
832 0 : {
833 0 : nsIFrame* rootFrame = shell->GetRootFrame();
834 : MOZ_ASSERT(rootFrame);
835 0 : if (this != rootFrame) {
836 0 : nsTArray<nsIFrame*>* modifiedFrames =
837 0 : rootFrame->GetProperty(nsIFrame::ModifiedFrameList());
838 : if (modifiedFrames) {
839 : MOZ_ASSERT(!modifiedFrames->Contains(this),
840 : "A dtor added this frame to ModifiedFrameList");
841 : }
842 : }
843 : }
844 : #endif
845 :
846 0 : // Now that we're totally cleaned out, we need to add ourselves to
847 0 : // the presshell's recycler.
848 : shell->FreeFrame(id, this);
849 : }
850 0 :
851 : nsresult
852 0 : nsFrame::GetOffsets(int32_t &aStart, int32_t &aEnd) const
853 0 : {
854 0 : aStart = 0;
855 : aEnd = 0;
856 : return NS_OK;
857 : }
858 0 :
859 : static void
860 : CompareLayers(const nsStyleImageLayers* aFirstLayers,
861 : const nsStyleImageLayers* aSecondLayers,
862 0 : const std::function<void(imgRequestProxy* aReq)>& aCallback)
863 0 : {
864 0 : NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aFirstLayers)) {
865 : const nsStyleImage& image = aFirstLayers->mLayers[i].mImage;
866 : if (image.GetType() != eStyleImageType_Image || !image.IsResolved()) {
867 : continue;
868 : }
869 :
870 0 : // aCallback is called when the style image in aFirstLayers is thought to
871 0 : // be different with the corresponded one in aSecondLayers
872 0 : if (!aSecondLayers || i >= aSecondLayers->mImageCount ||
873 0 : (!aSecondLayers->mLayers[i].mImage.IsResolved() ||
874 0 : !image.ImageDataEquals(aSecondLayers->mLayers[i].mImage))) {
875 : if (imgRequestProxy* req = image.GetImageData()) {
876 : aCallback(req);
877 : }
878 0 : }
879 : }
880 : }
881 0 :
882 : static void
883 : AddAndRemoveImageAssociations(nsFrame* aFrame,
884 : const nsStyleImageLayers* aOldLayers,
885 : const nsStyleImageLayers* aNewLayers)
886 0 : {
887 : ImageLoader* imageLoader =
888 : aFrame->PresContext()->Document()->StyleImageLoader();
889 :
890 : // If the old context had a background-image image, or mask-image image,
891 : // and new context does not have the same image, clear the image load
892 : // notifier (which keeps the image loading, if it still is) for the frame.
893 : // We want to do this conservatively because some frames paint their
894 : // backgrounds from some other frame's style data, and we don't want
895 : // to clear those notifiers unless we have to. (They'll be reset
896 0 : // when we paint, although we could miss a notification in that
897 0 : // interval.)
898 0 : if (aOldLayers && aFrame->HasImageRequest()) {
899 0 : CompareLayers(aOldLayers, aNewLayers,
900 0 : [&imageLoader, aFrame](imgRequestProxy* aReq)
901 : { imageLoader->DisassociateRequestFromFrame(aReq, aFrame); }
902 : );
903 0 : }
904 0 :
905 0 : CompareLayers(aNewLayers, aOldLayers,
906 0 : [&imageLoader, aFrame](imgRequestProxy* aReq)
907 0 : { imageLoader->AssociateRequestToFrame(aReq, aFrame, 0); }
908 : );
909 : }
910 0 :
911 : void
912 0 : nsIFrame::AddDisplayItem(nsDisplayItem* aItem)
913 0 : {
914 0 : DisplayItemArray* items = GetProperty(DisplayItems());
915 0 : if (!items) {
916 : items = new DisplayItemArray();
917 0 : AddProperty(DisplayItems(), items);
918 0 : }
919 0 : MOZ_DIAGNOSTIC_ASSERT(!items->Contains(aItem));
920 : items->AppendElement(aItem);
921 : }
922 0 :
923 : bool
924 0 : nsIFrame::RemoveDisplayItem(nsDisplayItem* aItem)
925 0 : {
926 : DisplayItemArray* items = GetProperty(DisplayItems());
927 : if (!items) {
928 0 : return false;
929 0 : }
930 0 : bool result = items->RemoveElement(aItem);
931 : if (items->IsEmpty()) {
932 : DeleteProperty(DisplayItems());
933 : }
934 : return result;
935 : }
936 0 :
937 : bool
938 0 : nsIFrame::HasDisplayItems()
939 0 : {
940 : DisplayItemArray* items = GetProperty(DisplayItems());
941 : return items != nullptr;
942 : }
943 0 :
944 : bool
945 0 : nsIFrame::HasDisplayItem(nsDisplayItem* aItem)
946 0 : {
947 : DisplayItemArray* items = GetProperty(DisplayItems());
948 : if (!items) {
949 0 : return false;
950 : }
951 : return items->Contains(aItem);
952 : }
953 0 :
954 : void
955 0 : nsIFrame::RemoveDisplayItemDataForDeletion()
956 0 : {
957 : FrameLayerBuilder::RemoveFrameFromLayerManager(this, DisplayItemData());
958 0 : DisplayItemData().Clear();
959 0 :
960 0 : DisplayItemArray* items = RemoveProperty(DisplayItems());
961 0 : if (items) {
962 0 : for (nsDisplayItem* i : *items) {
963 0 : if (i->GetDependentFrame() == this &&
964 : !i->HasDeletedFrame()) {
965 0 : i->Frame()->MarkNeedsDisplayItemRebuild();
966 : }
967 0 : i->RemoveFrame(this);
968 : }
969 : delete items;
970 0 : }
971 0 :
972 0 : if (IsFrameModified()) {
973 : nsIFrame* rootFrame = PresShell()->GetRootFrame();
974 : MOZ_ASSERT(rootFrame);
975 0 :
976 0 : nsTArray<nsIFrame*>* modifiedFrames =
977 : rootFrame->GetProperty(nsIFrame::ModifiedFrameList());
978 0 : MOZ_ASSERT(modifiedFrames);
979 0 :
980 0 : for (auto& frame : *modifiedFrames) {
981 0 : if (frame == this) {
982 : frame = nullptr;
983 : break;
984 : }
985 : }
986 0 : }
987 0 :
988 0 : if (HasOverrideDirtyRegion()) {
989 : nsIFrame* rootFrame = PresShell()->GetRootFrame();
990 : MOZ_ASSERT(rootFrame);
991 0 :
992 0 : nsTArray<nsIFrame*>* frames =
993 : rootFrame->GetProperty(nsIFrame::OverriddenDirtyRectFrameList());
994 0 : MOZ_ASSERT(frames);
995 0 :
996 0 : for (auto& frame : *frames) {
997 0 : if (frame == this) {
998 : frame = nullptr;
999 : break;
1000 : }
1001 0 : }
1002 : }
1003 : }
1004 0 :
1005 : void
1006 0 : nsIFrame::MarkNeedsDisplayItemRebuild()
1007 0 : {
1008 0 : if (!nsLayoutUtils::AreRetainedDisplayListsEnabled() ||
1009 : IsFrameModified() ||
1010 : HasAnyStateBits(NS_FRAME_IN_POPUP)) {
1011 : // Skip frames that are already marked modified.
1012 : return;
1013 0 : }
1014 0 :
1015 0 : if (Type() == LayoutFrameType::Placeholder) {
1016 0 : nsIFrame* oof = static_cast<nsPlaceholderFrame*>(this)->GetOutOfFlowFrame();
1017 : if (oof) {
1018 : oof->MarkNeedsDisplayItemRebuild();
1019 : }
1020 : // Do not mark placeholder frames modified.
1021 : return;
1022 0 : }
1023 0 :
1024 : nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
1025 : MOZ_ASSERT(displayRoot);
1026 0 :
1027 : RetainedDisplayListBuilder* retainedBuilder =
1028 0 : displayRoot->GetProperty(RetainedDisplayListBuilder::Cached());
1029 :
1030 : if (!retainedBuilder) {
1031 : return;
1032 0 : }
1033 0 :
1034 : nsIFrame* rootFrame = PresShell()->GetRootFrame();
1035 0 : MOZ_ASSERT(rootFrame);
1036 :
1037 : if (rootFrame->IsFrameModified()) {
1038 : return;
1039 : }
1040 0 :
1041 : nsTArray<nsIFrame*>* modifiedFrames =
1042 0 : rootFrame->GetProperty(nsIFrame::ModifiedFrameList());
1043 0 :
1044 0 : if (!modifiedFrames) {
1045 : modifiedFrames = new nsTArray<nsIFrame*>();
1046 : rootFrame->SetProperty(nsIFrame::ModifiedFrameList(), modifiedFrames);
1047 0 : }
1048 :
1049 : if (this == rootFrame) {
1050 : // If this is the root frame, then marking us as needing a display
1051 0 : // item rebuild implies the same for all our descendents. Clear them
1052 0 : // all out to reduce the number of modified frames we keep around.
1053 : for (nsIFrame* f : *modifiedFrames) {
1054 : if (f) {
1055 : f->SetFrameIsModified(false);
1056 0 : }
1057 0 : }
1058 : modifiedFrames->Clear();
1059 : } else if (modifiedFrames->Length() > gfxPrefs::LayoutRebuildFrameLimit()) {
1060 0 : // If the list starts getting too big, then just mark the root frame
1061 0 : // as needing a rebuild.
1062 : rootFrame->MarkNeedsDisplayItemRebuild();
1063 : return;
1064 0 : }
1065 :
1066 0 : modifiedFrames->AppendElement(this);
1067 0 :
1068 : MOZ_ASSERT(PresContext()->LayoutPhaseCount(eLayoutPhase_DisplayListBuilding) == 0);
1069 : SetFrameIsModified(true);
1070 :
1071 0 : // Hopefully this is cheap, but we could use a frame state bit to note
1072 0 : // the presence of dependencies to speed it up.
1073 0 : DisplayItemArray* items = GetProperty(DisplayItems());
1074 0 : if (items) {
1075 0 : for (nsDisplayItem* i : *items) {
1076 0 : if (i->GetDependentFrame() == this &&
1077 : !i->HasDeletedFrame()) {
1078 : i->Frame()->MarkNeedsDisplayItemRebuild();
1079 : }
1080 : }
1081 : }
1082 : }
1083 :
1084 0 : // Subclass hook for style post processing
1085 : /* virtual */ void
1086 0 : nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle)
1087 : {
1088 0 : if (nsSVGUtils::IsInSVGTextSubtree(this)) {
1089 0 : SVGTextFrame* svgTextFrame = static_cast<SVGTextFrame*>(
1090 : nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::SVGText));
1091 : nsIFrame* anonBlock = svgTextFrame->PrincipalChildList().FirstChild();
1092 : // Just as in SVGTextFrame::DidSetComputedStyle, we need to ensure that
1093 : // any non-display SVGTextFrames get reflowed when a child text frame
1094 : // gets new style.
1095 : //
1096 : // Note that we must check NS_FRAME_FIRST_REFLOW on our SVGTextFrame's
1097 : // anonymous block frame rather than our self, since NS_FRAME_FIRST_REFLOW
1098 : // may be set on us if we're a new frame that has been inserted after the
1099 0 : // document's first reflow. (In which case this DidSetComputedStyle call may
1100 0 : // be happening under frame construction under a Reflow() call.)
1101 0 : if (anonBlock && !(anonBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
1102 0 : (svgTextFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY) &&
1103 : !(svgTextFrame->GetStateBits() & NS_STATE_SVG_TEXT_IN_REFLOW)) {
1104 : svgTextFrame->ScheduleReflowSVGNonDisplayText(nsIPresShell::eStyleChange);
1105 : }
1106 0 : }
1107 0 :
1108 0 : const nsStyleImageLayers *oldLayers = aOldComputedStyle ?
1109 0 : &aOldComputedStyle->StyleBackground()->mImage :
1110 0 : nullptr;
1111 : const nsStyleImageLayers *newLayers = &StyleBackground()->mImage;
1112 0 : AddAndRemoveImageAssociations(this, oldLayers, newLayers);
1113 :
1114 0 : oldLayers = aOldComputedStyle ? &aOldComputedStyle->StyleSVGReset()->mMask :
1115 0 : nullptr;
1116 : newLayers = &StyleSVGReset()->mMask;
1117 0 : AddAndRemoveImageAssociations(this, oldLayers, newLayers);
1118 :
1119 : if (aOldComputedStyle) {
1120 : // If we detect a change on margin, padding or border, we store the old
1121 : // values on the frame itself between now and reflow, so if someone
1122 : // calls GetUsed(Margin|Border|Padding)() before the next reflow, we
1123 0 : // can give an accurate answer.
1124 0 : // We don't want to set the property if one already exists.
1125 0 : nsMargin oldValue(0, 0, 0, 0);
1126 0 : nsMargin newValue(0, 0, 0, 0);
1127 0 : const nsStyleMargin* oldMargin = aOldComputedStyle->PeekStyleMargin();
1128 0 : if (oldMargin && oldMargin->GetMargin(oldValue)) {
1129 0 : if ((!StyleMargin()->GetMargin(newValue) || oldValue != newValue) &&
1130 : !HasProperty(UsedMarginProperty())) {
1131 : AddProperty(UsedMarginProperty(), new nsMargin(oldValue));
1132 : }
1133 0 : }
1134 0 :
1135 0 : const nsStylePadding* oldPadding = aOldComputedStyle->PeekStylePadding();
1136 0 : if (oldPadding && oldPadding->GetPadding(oldValue)) {
1137 0 : if ((!StylePadding()->GetPadding(newValue) || oldValue != newValue) &&
1138 : !HasProperty(UsedPaddingProperty())) {
1139 : AddProperty(UsedPaddingProperty(), new nsMargin(oldValue));
1140 : }
1141 0 : }
1142 0 :
1143 0 : const nsStyleBorder* oldBorder = aOldComputedStyle->PeekStyleBorder();
1144 0 : if (oldBorder) {
1145 0 : oldValue = oldBorder->GetComputedBorder();
1146 0 : newValue = StyleBorder()->GetComputedBorder();
1147 0 : if (oldValue != newValue &&
1148 : !HasProperty(UsedBorderProperty())) {
1149 : AddProperty(UsedBorderProperty(), new nsMargin(oldValue));
1150 : }
1151 : }
1152 0 : }
1153 :
1154 0 : ImageLoader* imageLoader = PresContext()->Document()->StyleImageLoader();
1155 0 : imgIRequest *oldBorderImage = aOldComputedStyle
1156 0 : ? aOldComputedStyle->StyleBorder()->GetBorderImageRequest()
1157 : : nullptr;
1158 : imgIRequest *newBorderImage = StyleBorder()->GetBorderImageRequest();
1159 : // FIXME (Bug 759996): The following is no longer true.
1160 : // For border-images, we can't be as conservative (we need to set the
1161 : // new loaders if there has been any change) since the CalcDifference
1162 : // call depended on the result of GetComputedBorder() and that result
1163 : // depends on whether the image has loaded, start the image load now
1164 : // so that we'll get notified when it completes loading and can do a
1165 : // restyle. Otherwise, the image might finish loading from the
1166 : // network before we start listening to its notifications, and then
1167 : // we'll never know that it's finished loading. Likewise, we want to
1168 : // do this for freshly-created frames to prevent a similar race if the
1169 : // image loads between reflow (which can depend on whether the image
1170 : // is loaded) and paint. We also don't really care about any callers who try
1171 0 : // to paint borders with a different style, because they won't have the
1172 : // correct size for the border either.
1173 0 : if (oldBorderImage != newBorderImage) {
1174 0 : // stop and restart the image loading/notification
1175 : if (oldBorderImage && HasImageRequest()) {
1176 0 : imageLoader->DisassociateRequestFromFrame(oldBorderImage, this);
1177 0 : }
1178 : if (newBorderImage) {
1179 : imageLoader->AssociateRequestToFrame(newBorderImage, this, 0);
1180 : }
1181 : }
1182 :
1183 0 : imgIRequest* oldShapeImage =
1184 0 : aOldComputedStyle
1185 : ? aOldComputedStyle->StyleDisplay()->mShapeOutside.GetShapeImageData()
1186 0 : : nullptr;
1187 : imgIRequest* newShapeImage =
1188 0 : StyleDisplay()->mShapeOutside.GetShapeImageData();
1189 0 :
1190 0 : if (oldShapeImage != newShapeImage) {
1191 : if (oldShapeImage && HasImageRequest()) {
1192 0 : imageLoader->DisassociateRequestFromFrame(oldShapeImage, this);
1193 : }
1194 0 : if (newShapeImage) {
1195 : imageLoader->AssociateRequestToFrame(newShapeImage, this,
1196 : ImageLoader::REQUEST_REQUIRES_REFLOW);
1197 : }
1198 : }
1199 :
1200 : // If the page contains markup that overrides text direction, and
1201 : // does not contain any characters that would activate the Unicode
1202 0 : // bidi algorithm, we need to call |SetBidiEnabled| on the pres
1203 0 : // context before reflow starts. See bug 115921.
1204 : if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
1205 : PresContext()->SetBidiEnabled();
1206 0 : }
1207 0 :
1208 : RemoveStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS |
1209 0 : NS_FRAME_SIMPLE_DISPLAYLIST);
1210 0 :
1211 : mMayHaveRoundedCorners = true;
1212 : }
1213 0 :
1214 : void
1215 : nsIFrame::ReparentFrameViewTo(nsViewManager* aViewManager,
1216 : nsView* aNewParentView,
1217 0 : nsView* aOldParentView)
1218 : {
1219 0 : if (HasView()) {
1220 : #ifdef MOZ_XUL
1221 : if (IsMenuPopupFrame()) {
1222 : // This view must be parented by the root view, don't reparent it.
1223 : return;
1224 0 : }
1225 : #endif
1226 : nsView* view = GetView();
1227 : // Verify that the current parent view is what we think it is
1228 : //nsView* parentView;
1229 0 : //NS_ASSERTION(parentView == aOldParentView, "unexpected parent view");
1230 :
1231 : aViewManager->RemoveChild(view);
1232 0 :
1233 0 : // The view will remember the Z-order and other attributes that have been set on it.
1234 0 : nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(aNewParentView, this);
1235 0 : aViewManager->InsertChild(aNewParentView, view, insertBefore, insertBefore != nullptr);
1236 0 : } else if (GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW) {
1237 : nsIFrame::ChildListIterator lists(this);
1238 : for (; !lists.IsDone(); lists.Next()) {
1239 0 : // Iterate the child frames, and check each child frame to see if it has
1240 0 : // a view
1241 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
1242 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
1243 : childFrames.get()->ReparentFrameViewTo(aViewManager, aNewParentView,
1244 : aOldParentView);
1245 : }
1246 : }
1247 : }
1248 : }
1249 0 :
1250 : void
1251 0 : nsIFrame::SyncFrameViewProperties(nsView* aView)
1252 0 : {
1253 0 : if (!aView) {
1254 : aView = GetView();
1255 : if (!aView) {
1256 : return;
1257 : }
1258 0 : }
1259 :
1260 : nsViewManager* vm = aView->GetViewManager();
1261 0 :
1262 : // Make sure visibility is correct. This only affects nsSubDocumentFrame.
1263 0 : if (!SupportsVisibilityHidden()) {
1264 0 : // See if the view should be hidden or visible
1265 0 : ComputedStyle* sc = Style();
1266 0 : vm->SetViewVisibility(aView,
1267 : sc->StyleVisibility()->IsVisible()
1268 : ? nsViewVisibility_kShow : nsViewVisibility_kHide);
1269 0 : }
1270 0 :
1271 : int32_t zIndex = 0;
1272 0 : bool autoZIndex = false;
1273 :
1274 0 : if (IsAbsPosContainingBlock()) {
1275 0 : // Make sure z-index is correct
1276 0 : ComputedStyle* sc = Style();
1277 0 : const nsStylePosition* position = sc->StylePosition();
1278 0 : if (position->mZIndex.GetUnit() == eStyleUnit_Integer) {
1279 0 : zIndex = position->mZIndex.GetIntValue();
1280 : } else if (position->mZIndex.GetUnit() == eStyleUnit_Auto) {
1281 : autoZIndex = true;
1282 : }
1283 : } else {
1284 : autoZIndex = true;
1285 0 : }
1286 :
1287 : vm->SetViewZIndex(aView, autoZIndex, zIndex);
1288 : }
1289 0 :
1290 : void
1291 0 : nsFrame::CreateView()
1292 : {
1293 0 : MOZ_ASSERT(!HasView());
1294 0 :
1295 : nsView* parentView = GetParent()->GetClosestView();
1296 0 : MOZ_ASSERT(parentView, "no parent with view");
1297 0 :
1298 : nsViewManager* viewManager = parentView->GetViewManager();
1299 0 : MOZ_ASSERT(viewManager, "null view manager");
1300 0 :
1301 : nsView* view = viewManager->CreateView(GetRect(), parentView);
1302 0 : SyncFrameViewProperties(view);
1303 :
1304 : nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(parentView, this);
1305 : // we insert this view 'above' the insertBefore view, unless insertBefore is null,
1306 0 : // in which case we want to call with aAbove == false to insert at the beginning
1307 : // in document order
1308 : viewManager->InsertChild(parentView, view, insertBefore, insertBefore != nullptr);
1309 :
1310 : // REVIEW: Don't create a widget for fixed-pos elements anymore.
1311 : // ComputeRepaintRegionForCopy will calculate the right area to repaint
1312 : // when we scroll.
1313 : // Reparent views on any child frames (or their descendants) to this
1314 : // view. We can just call ReparentFrameViewTo on this frame because
1315 : // we know this frame has no view, so it will crawl the children. Also,
1316 0 : // we know that any descendants with views must have 'parentView' as their
1317 : // parent view.
1318 : ReparentFrameViewTo(viewManager, view, parentView);
1319 0 :
1320 : // Remember our view
1321 0 : SetView(view);
1322 :
1323 : NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
1324 0 : ("nsFrame::CreateView: frame=%p view=%p",
1325 : this, view));
1326 : }
1327 :
1328 : // MSVC fails with link error "one or more multiply defined symbols found",
1329 : // gcc fails with "hidden symbol `nsIFrame::kPrincipalList' isn't defined"
1330 : // etc if they are not defined.
1331 : #ifndef _MSC_VER
1332 : // static nsIFrame constants; initialized in the header file.
1333 : const nsIFrame::ChildListID nsIFrame::kPrincipalList;
1334 : const nsIFrame::ChildListID nsIFrame::kAbsoluteList;
1335 : const nsIFrame::ChildListID nsIFrame::kBulletList;
1336 : const nsIFrame::ChildListID nsIFrame::kCaptionList;
1337 : const nsIFrame::ChildListID nsIFrame::kColGroupList;
1338 : const nsIFrame::ChildListID nsIFrame::kExcessOverflowContainersList;
1339 : const nsIFrame::ChildListID nsIFrame::kFixedList;
1340 : const nsIFrame::ChildListID nsIFrame::kFloatList;
1341 : const nsIFrame::ChildListID nsIFrame::kOverflowContainersList;
1342 : const nsIFrame::ChildListID nsIFrame::kOverflowList;
1343 : const nsIFrame::ChildListID nsIFrame::kOverflowOutOfFlowList;
1344 : const nsIFrame::ChildListID nsIFrame::kPopupList;
1345 : const nsIFrame::ChildListID nsIFrame::kPushedFloatsList;
1346 : const nsIFrame::ChildListID nsIFrame::kSelectPopupList;
1347 : const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList;
1348 : #endif
1349 0 :
1350 : /* virtual */ nsMargin
1351 0 : nsIFrame::GetUsedMargin() const
1352 0 : {
1353 0 : nsMargin margin(0, 0, 0, 0);
1354 0 : if (((mState & NS_FRAME_FIRST_REFLOW) &&
1355 : !(mState & NS_FRAME_IN_REFLOW)) ||
1356 : nsSVGUtils::IsInSVGTextSubtree(this))
1357 0 : return margin;
1358 0 :
1359 0 : nsMargin *m = GetProperty(UsedMarginProperty());
1360 : if (m) {
1361 0 : margin = *m;
1362 : } else {
1363 0 : if (!StyleMargin()->GetMargin(margin)) {
1364 : // If we get here, our caller probably shouldn't be calling us...
1365 : NS_ERROR("Returning bogus 0-sized margin, because this margin "
1366 : "depends on layout & isn't cached!");
1367 : }
1368 : }
1369 : return margin;
1370 : }
1371 0 :
1372 : /* virtual */ nsMargin
1373 0 : nsIFrame::GetUsedBorder() const
1374 0 : {
1375 0 : nsMargin border(0, 0, 0, 0);
1376 0 : if (((mState & NS_FRAME_FIRST_REFLOW) &&
1377 : !(mState & NS_FRAME_IN_REFLOW)) ||
1378 : nsSVGUtils::IsInSVGTextSubtree(this))
1379 : return border;
1380 0 :
1381 : // Theme methods don't use const-ness.
1382 0 : nsIFrame* mutable_this = const_cast<nsIFrame*>(this);
1383 0 :
1384 0 : const nsStyleDisplay* disp = StyleDisplay();
1385 : if (mutable_this->IsThemed(disp)) {
1386 0 : nsPresContext* pc = PresContext();
1387 0 : LayoutDeviceIntMargin widgetBorder =
1388 0 : pc->GetTheme()->GetWidgetBorder(pc->DeviceContext(), mutable_this,
1389 : disp->mAppearance);
1390 : border = LayoutDevicePixel::ToAppUnits(widgetBorder,
1391 : pc->AppUnitsPerDevPixel());
1392 : return border;
1393 0 : }
1394 0 :
1395 0 : nsMargin* b = GetProperty(UsedBorderProperty());
1396 : if (b) {
1397 0 : border = *b;
1398 : } else {
1399 : border = StyleBorder()->GetComputedBorder();
1400 : }
1401 : return border;
1402 : }
1403 0 :
1404 : /* virtual */ nsMargin
1405 0 : nsIFrame::GetUsedPadding() const
1406 0 : {
1407 0 : nsMargin padding(0, 0, 0, 0);
1408 0 : if (((mState & NS_FRAME_FIRST_REFLOW) &&
1409 : !(mState & NS_FRAME_IN_REFLOW)) ||
1410 : nsSVGUtils::IsInSVGTextSubtree(this))
1411 : return padding;
1412 0 :
1413 : // Theme methods don't use const-ness.
1414 0 : nsIFrame* mutable_this = const_cast<nsIFrame*>(this);
1415 0 :
1416 0 : const nsStyleDisplay* disp = StyleDisplay();
1417 0 : if (mutable_this->IsThemed(disp)) {
1418 0 : nsPresContext* pc = PresContext();
1419 0 : LayoutDeviceIntMargin widgetPadding;
1420 : if (pc->GetTheme()->GetWidgetPadding(pc->DeviceContext(), mutable_this,
1421 0 : disp->mAppearance, &widgetPadding)) {
1422 : return LayoutDevicePixel::ToAppUnits(widgetPadding,
1423 : pc->AppUnitsPerDevPixel());
1424 : }
1425 0 : }
1426 0 :
1427 0 : nsMargin* p = GetProperty(UsedPaddingProperty());
1428 : if (p) {
1429 0 : padding = *p;
1430 : } else {
1431 0 : if (!StylePadding()->GetPadding(padding)) {
1432 : // If we get here, our caller probably shouldn't be calling us...
1433 : NS_ERROR("Returning bogus 0-sized padding, because this padding "
1434 : "depends on layout & isn't cached!");
1435 : }
1436 : }
1437 : return padding;
1438 : }
1439 0 :
1440 : nsIFrame::Sides
1441 0 : nsIFrame::GetSkipSides(const ReflowInput* aReflowInput) const
1442 0 : {
1443 0 : if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
1444 0 : StyleBoxDecorationBreak::Clone) &&
1445 : !(GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1446 : return Sides();
1447 : }
1448 :
1449 0 : // Convert the logical skip sides to physical sides using the frame's
1450 0 : // writing mode
1451 0 : WritingMode writingMode = GetWritingMode();
1452 : LogicalSides logicalSkip = GetLogicalSkipSides(aReflowInput);
1453 0 : Sides skip;
1454 0 :
1455 0 : if (logicalSkip.BStart()) {
1456 : if (writingMode.IsVertical()) {
1457 0 : skip |= writingMode.IsVerticalLR() ? eSideBitsLeft : eSideBitsRight;
1458 : } else {
1459 : skip |= eSideBitsTop;
1460 : }
1461 0 : }
1462 0 :
1463 0 : if (logicalSkip.BEnd()) {
1464 : if (writingMode.IsVertical()) {
1465 0 : skip |= writingMode.IsVerticalLR() ? eSideBitsRight : eSideBitsLeft;
1466 : } else {
1467 : skip |= eSideBitsBottom;
1468 : }
1469 0 : }
1470 0 :
1471 0 : if (logicalSkip.IStart()) {
1472 : if (writingMode.IsVertical()) {
1473 0 : skip |= eSideBitsTop;
1474 : } else {
1475 : skip |= writingMode.IsBidiLTR() ? eSideBitsLeft : eSideBitsRight;
1476 : }
1477 0 : }
1478 0 :
1479 0 : if (logicalSkip.IEnd()) {
1480 : if (writingMode.IsVertical()) {
1481 0 : skip |= eSideBitsBottom;
1482 : } else {
1483 : skip |= writingMode.IsBidiLTR() ? eSideBitsRight : eSideBitsLeft;
1484 0 : }
1485 : }
1486 : return skip;
1487 : }
1488 0 :
1489 : nsRect
1490 0 : nsIFrame::GetPaddingRectRelativeToSelf() const
1491 0 : {
1492 0 : nsMargin border(GetUsedBorder());
1493 0 : border.ApplySkipSides(GetSkipSides());
1494 0 : nsRect r(0, 0, mRect.width, mRect.height);
1495 : r.Deflate(border);
1496 : return r;
1497 : }
1498 0 :
1499 : nsRect
1500 0 : nsIFrame::GetPaddingRect() const
1501 : {
1502 : return GetPaddingRectRelativeToSelf() + GetPosition();
1503 : }
1504 0 :
1505 : WritingMode
1506 : nsIFrame::WritingModeForLine(WritingMode aSelfWM,
1507 0 : nsIFrame* aSubFrame) const
1508 0 : {
1509 : MOZ_ASSERT(aSelfWM == GetWritingMode());
1510 0 : WritingMode writingMode = aSelfWM;
1511 0 :
1512 0 : if (StyleTextReset()->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_PLAINTEXT) {
1513 : nsBidiLevel frameLevel = nsBidiPresUtils::GetFrameBaseLevel(aSubFrame);
1514 : writingMode.SetDirectionFromBidiLevel(frameLevel);
1515 0 : }
1516 :
1517 : return writingMode;
1518 : }
1519 0 :
1520 : nsRect
1521 0 : nsIFrame::GetMarginRectRelativeToSelf() const
1522 0 : {
1523 0 : nsMargin m = GetUsedMargin();
1524 0 : m.ApplySkipSides(GetSkipSides());
1525 0 : nsRect r(0, 0, mRect.width, mRect.height);
1526 : r.Inflate(m);
1527 : return r;
1528 : }
1529 0 :
1530 : bool
1531 0 : nsIFrame::IsTransformed(const nsStyleDisplay* aStyleDisplay) const
1532 0 : {
1533 : return IsCSSTransformed(aStyleDisplay) ||
1534 : IsSVGTransformed();
1535 : }
1536 0 :
1537 : bool
1538 0 : nsIFrame::IsCSSTransformed(const nsStyleDisplay* aStyleDisplay) const
1539 0 : {
1540 0 : MOZ_ASSERT(aStyleDisplay == StyleDisplay());
1541 0 : return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
1542 : (aStyleDisplay->HasTransform(this) ||
1543 : HasAnimationOfTransform()));
1544 : }
1545 0 :
1546 : bool
1547 : nsIFrame::HasAnimationOfTransform() const
1548 0 : {
1549 0 :
1550 0 : return IsPrimaryFrame() &&
1551 : nsLayoutUtils::HasAnimationOfProperty(this, eCSSProperty_transform) &&
1552 : IsFrameOfType(eSupportsCSSTransforms);
1553 : }
1554 0 :
1555 : bool
1556 0 : nsIFrame::ChildrenHavePerspective(const nsStyleDisplay* aStyleDisplay) const
1557 0 : {
1558 : MOZ_ASSERT(aStyleDisplay == StyleDisplay());
1559 : return aStyleDisplay->HasPerspective(this);
1560 : }
1561 0 :
1562 : bool
1563 : nsIFrame::HasOpacityInternal(float aThreshold,
1564 0 : EffectSet* aEffectSet) const
1565 0 : {
1566 0 : MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
1567 : if (StyleEffects()->mOpacity < aThreshold ||
1568 : (StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY)) {
1569 : return true;
1570 0 : }
1571 :
1572 : if (!mMayHaveOpacityAnimation) {
1573 : return false;
1574 : }
1575 0 :
1576 0 : EffectSet* effects =
1577 : aEffectSet ? aEffectSet : EffectSet::GetEffectSet(this);
1578 : if (!effects) {
1579 : return false;
1580 0 : }
1581 :
1582 0 : return ((IsPrimaryFrame() ||
1583 0 : nsLayoutUtils::FirstContinuationOrIBSplitSibling(this)->
1584 : IsPrimaryFrame()) &&
1585 : nsLayoutUtils::HasAnimationOfProperty(effects, eCSSProperty_opacity));
1586 : }
1587 0 :
1588 : bool
1589 : nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
1590 0 : gfx::Matrix *aFromParentTransforms) const
1591 : {
1592 : return false;
1593 : }
1594 0 :
1595 : bool
1596 0 : nsIFrame::Extend3DContext(const nsStyleDisplay* aStyleDisplay, mozilla::EffectSet* aEffectSet) const
1597 : {
1598 : if (!(mState & NS_FRAME_MAY_BE_TRANSFORMED)) {
1599 0 : return false;
1600 0 : }
1601 0 : const nsStyleDisplay* disp = StyleDisplayWithOptionalParam(aStyleDisplay);
1602 : if (disp->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
1603 : !IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) {
1604 : return false;
1605 : }
1606 0 :
1607 : // If we're all scroll frame, then all descendants will be clipped, so we can't preserve 3d.
1608 : if (IsScrollFrame()) {
1609 : return false;
1610 0 : }
1611 :
1612 : if (HasOpacity(aEffectSet)) {
1613 : return false;
1614 0 : }
1615 0 :
1616 0 : const nsStyleEffects* effects = StyleEffects();
1617 0 : return !nsFrame::ShouldApplyOverflowClipping(this, disp) &&
1618 : !GetClipPropClipRect(disp, effects, GetSize()) &&
1619 : !nsSVGIntegrationUtils::UsingEffectsForFrame(this);
1620 : }
1621 0 :
1622 : bool
1623 0 : nsIFrame::Combines3DTransformWithAncestors(const nsStyleDisplay* aStyleDisplay) const
1624 0 : {
1625 0 : MOZ_ASSERT(aStyleDisplay == StyleDisplay());
1626 : nsIFrame* parent = GetInFlowParent();
1627 : if (!parent || !parent->Extend3DContext()) {
1628 0 : return false;
1629 0 : }
1630 : return IsCSSTransformed(aStyleDisplay) ||
1631 : BackfaceIsHidden(aStyleDisplay);
1632 : }
1633 0 :
1634 : bool
1635 : nsIFrame::In3DContextAndBackfaceIsHidden() const
1636 : {
1637 0 : // While both tests fail most of the time, test BackfaceIsHidden()
1638 0 : // first since it's likely to fail faster.
1639 0 : const nsStyleDisplay* disp = StyleDisplay();
1640 : return BackfaceIsHidden(disp) &&
1641 : Combines3DTransformWithAncestors(disp);
1642 : }
1643 0 :
1644 : bool
1645 0 : nsIFrame::HasPerspective(const nsStyleDisplay* aStyleDisplay) const
1646 0 : {
1647 : MOZ_ASSERT(aStyleDisplay == StyleDisplay());
1648 : if (!IsTransformed(aStyleDisplay)) {
1649 0 : return false;
1650 0 : }
1651 : nsIFrame* containingBlock = GetContainingBlock(SKIP_SCROLLED_FRAME, aStyleDisplay);
1652 : if (!containingBlock) {
1653 0 : return false;
1654 : }
1655 : return containingBlock->ChildrenHavePerspective();
1656 : }
1657 0 :
1658 : nsRect
1659 0 : nsIFrame::GetContentRectRelativeToSelf() const
1660 0 : {
1661 0 : nsMargin bp(GetUsedBorderAndPadding());
1662 0 : bp.ApplySkipSides(GetSkipSides());
1663 0 : nsRect r(0, 0, mRect.width, mRect.height);
1664 : r.Deflate(bp);
1665 : return r;
1666 : }
1667 0 :
1668 : nsRect
1669 0 : nsIFrame::GetContentRect() const
1670 : {
1671 : return GetContentRectRelativeToSelf() + GetPosition();
1672 : }
1673 0 :
1674 : bool
1675 : nsIFrame::ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
1676 : const nsSize& aFrameSize,
1677 : const nsSize& aBorderArea,
1678 : Sides aSkipSides,
1679 : nscoord aRadii[8])
1680 0 : {
1681 0 : // Percentages are relative to whichever side they're on.
1682 : NS_FOR_CSS_HALF_CORNERS(i) {
1683 0 : const nsStyleCoord c = aBorderRadius.Get(i);
1684 : nscoord axis =
1685 0 : HalfCornerIsX(i) ? aFrameSize.width : aFrameSize.height;
1686 0 :
1687 0 : if (c.IsCoordPercentCalcUnit()) {
1688 : aRadii[i] = c.ComputeCoordPercentCalc(axis);
1689 0 : if (aRadii[i] < 0) {
1690 : // clamp calc()
1691 : aRadii[i] = 0;
1692 0 : }
1693 0 : } else {
1694 : NS_NOTREACHED("ComputeBorderRadii: bad unit");
1695 : aRadii[i] = 0;
1696 : }
1697 0 : }
1698 0 :
1699 0 : if (aSkipSides.Top()) {
1700 0 : aRadii[eCornerTopLeftX] = 0;
1701 0 : aRadii[eCornerTopLeftY] = 0;
1702 : aRadii[eCornerTopRightX] = 0;
1703 : aRadii[eCornerTopRightY] = 0;
1704 0 : }
1705 0 :
1706 0 : if (aSkipSides.Right()) {
1707 0 : aRadii[eCornerTopRightX] = 0;
1708 0 : aRadii[eCornerTopRightY] = 0;
1709 : aRadii[eCornerBottomRightX] = 0;
1710 : aRadii[eCornerBottomRightY] = 0;
1711 0 : }
1712 0 :
1713 0 : if (aSkipSides.Bottom()) {
1714 0 : aRadii[eCornerBottomRightX] = 0;
1715 0 : aRadii[eCornerBottomRightY] = 0;
1716 : aRadii[eCornerBottomLeftX] = 0;
1717 : aRadii[eCornerBottomLeftY] = 0;
1718 0 : }
1719 0 :
1720 0 : if (aSkipSides.Left()) {
1721 0 : aRadii[eCornerBottomLeftX] = 0;
1722 0 : aRadii[eCornerBottomLeftY] = 0;
1723 : aRadii[eCornerTopLeftX] = 0;
1724 : aRadii[eCornerTopLeftY] = 0;
1725 : }
1726 :
1727 0 : // css3-background specifies this algorithm for reducing
1728 0 : // corner radii when they are too big.
1729 0 : bool haveRadius = false;
1730 0 : double ratio = 1.0f;
1731 0 : NS_FOR_CSS_SIDES(side) {
1732 : uint32_t hc1 = SideToHalfCorner(side, false, true);
1733 0 : uint32_t hc2 = SideToHalfCorner(side, true, true);
1734 0 : nscoord length =
1735 0 : SideIsVertical(side) ? aBorderArea.height : aBorderArea.width;
1736 0 : nscoord sum = aRadii[hc1] + aRadii[hc2];
1737 : if (sum)
1738 : haveRadius = true;
1739 0 :
1740 0 : // avoid floating point division in the normal case
1741 : if (length < sum)
1742 0 : ratio = std::min(ratio, double(length)/sum);
1743 0 : }
1744 0 : if (ratio < 1.0) {
1745 : NS_FOR_CSS_HALF_CORNERS(corner) {
1746 : aRadii[corner] *= ratio;
1747 : }
1748 0 : }
1749 :
1750 : return haveRadius;
1751 : }
1752 0 :
1753 : /* static */ void
1754 0 : nsIFrame::InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
1755 0 : {
1756 0 : NS_FOR_CSS_SIDES(side) {
1757 0 : nscoord offset = aOffsets.Side(side);
1758 0 : uint32_t hc1 = SideToHalfCorner(side, false, false);
1759 0 : uint32_t hc2 = SideToHalfCorner(side, true, false);
1760 : aRadii[hc1] = std::max(0, aRadii[hc1] - offset);
1761 0 : aRadii[hc2] = std::max(0, aRadii[hc2] - offset);
1762 : }
1763 : }
1764 0 :
1765 : /* static */ void
1766 0 : nsIFrame::OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
1767 : {
1768 : auto AdjustOffset = [] (const uint32_t aRadius, const nscoord aOffset) {
1769 : // Implement the cubic formula to adjust offset when aOffset > 0 and
1770 0 : // aRadius / aOffset < 1.
1771 0 : // https://drafts.csswg.org/css-shapes/#valdef-shape-box-margin-box
1772 0 : if (aOffset > 0) {
1773 0 : const double ratio = aRadius / double(aOffset);
1774 : if (ratio < 1.0) {
1775 : return nscoord(aOffset * (1.0 + std::pow(ratio - 1, 3)));
1776 : }
1777 : }
1778 : return aOffset;
1779 0 : };
1780 0 :
1781 0 : NS_FOR_CSS_SIDES(side) {
1782 0 : const nscoord offset = aOffsets.Side(side);
1783 0 : const uint32_t hc1 = SideToHalfCorner(side, false, false);
1784 0 : const uint32_t hc2 = SideToHalfCorner(side, true, false);
1785 0 : if (aRadii[hc1] > 0) {
1786 : const nscoord offset1 = AdjustOffset(aRadii[hc1], offset);
1787 0 : aRadii[hc1] = std::max(0, aRadii[hc1] + offset1);
1788 0 : }
1789 0 : if (aRadii[hc2] > 0) {
1790 : const nscoord offset2 = AdjustOffset(aRadii[hc2], offset);
1791 : aRadii[hc2] = std::max(0, aRadii[hc2] + offset2);
1792 0 : }
1793 : }
1794 : }
1795 0 :
1796 : /* virtual */ bool
1797 : nsIFrame::GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
1798 0 : Sides aSkipSides, nscoord aRadii[8]) const
1799 0 : {
1800 0 : if (!mMayHaveRoundedCorners) {
1801 : memset(aRadii, 0, sizeof(nscoord) * 8);
1802 : return false;
1803 0 : }
1804 :
1805 : if (IsThemed()) {
1806 : // When we're themed, the native theme code draws the border and
1807 : // background, and therefore it doesn't make sense to tell other
1808 : // code that's interested in border-radius that we have any radii.
1809 : //
1810 : // In an ideal world, we might have a way for the them to tell us an
1811 0 : // border radius, but since we don't, we're better off assuming
1812 0 : // zero.
1813 : NS_FOR_CSS_HALF_CORNERS(corner) {
1814 : aRadii[corner] = 0;
1815 : }
1816 : return false;
1817 0 : }
1818 0 :
1819 : const_cast<nsIFrame*>(this)->mMayHaveRoundedCorners =
1820 : ComputeBorderRadii(StyleBorder()->mBorderRadius,
1821 0 : aFrameSize, aBorderArea,
1822 : aSkipSides, aRadii);
1823 : return mMayHaveRoundedCorners;
1824 : }
1825 0 :
1826 : bool
1827 0 : nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
1828 0 : {
1829 : nsSize sz = GetSize();
1830 : return GetBorderRadii(sz, sz, GetSkipSides(), aRadii);
1831 : }
1832 0 :
1833 : bool
1834 0 : nsIFrame::GetMarginBoxBorderRadii(nscoord aRadii[8]) const
1835 : {
1836 : return GetBoxBorderRadii(aRadii, GetUsedMargin(), true);
1837 : }
1838 0 :
1839 : bool
1840 58 : nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const
1841 : {
1842 : return GetBoxBorderRadii(aRadii, GetUsedBorder(), false);
1843 : }
1844 99 :
1845 : bool
1846 99 : nsIFrame::GetContentBoxBorderRadii(nscoord aRadii[8]) const
1847 : {
1848 : return GetBoxBorderRadii(aRadii, GetUsedBorderAndPadding(), false);
1849 : }
1850 189 :
1851 : bool
1852 0 : nsIFrame::GetBoxBorderRadii(nscoord aRadii[8], nsMargin aOffset, bool aIsOutset) const
1853 : {
1854 64 : if (!GetBorderRadii(aRadii))
1855 0 : return false;
1856 : if (aIsOutset) {
1857 64 : OutsetBorderRadii(aRadii, aOffset);
1858 : } else {
1859 448 : InsetBorderRadii(aRadii, aOffset);
1860 0 : }
1861 : NS_FOR_CSS_HALF_CORNERS(corner) {
1862 : if (aRadii[corner])
1863 : return true;
1864 : }
1865 : return false;
1866 : }
1867 0 :
1868 : bool
1869 0 : nsIFrame::GetShapeBoxBorderRadii(nscoord aRadii[8]) const
1870 : {
1871 : switch (StyleDisplay()->mShapeOutside.GetReferenceBox()) {
1872 : case StyleGeometryBox::NoBox:
1873 0 : return false;
1874 : case StyleGeometryBox::ContentBox:
1875 0 : return GetContentBoxBorderRadii(aRadii);
1876 : case StyleGeometryBox::PaddingBox:
1877 0 : return GetPaddingBoxBorderRadii(aRadii);
1878 : case StyleGeometryBox::BorderBox:
1879 0 : return GetBorderRadii(aRadii);
1880 : case StyleGeometryBox::MarginBox:
1881 0 : return GetMarginBoxBorderRadii(aRadii);
1882 : default:
1883 : MOZ_ASSERT_UNREACHABLE("Unexpected box value");
1884 : return false;
1885 : }
1886 : }
1887 1 :
1888 : ComputedStyle*
1889 102 : nsFrame::GetAdditionalComputedStyle(int32_t aIndex) const
1890 102 : {
1891 : MOZ_ASSERT(aIndex >= 0, "invalid index number");
1892 : return nullptr;
1893 : }
1894 0 :
1895 : void
1896 : nsFrame::SetAdditionalComputedStyle(int32_t aIndex,
1897 0 : ComputedStyle* aComputedStyle)
1898 0 : {
1899 : MOZ_ASSERT(aIndex >= 0, "invalid index number");
1900 : }
1901 81 :
1902 : nscoord
1903 1 : nsFrame::GetLogicalBaseline(WritingMode aWritingMode) const
1904 : {
1905 : NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
1906 : "frame must not be dirty");
1907 0 : // Baseline for inverted line content is the top (block-start) margin edge,
1908 0 : // as the frame is in effect "flipped" for alignment purposes.
1909 : if (aWritingMode.IsLineInverted()) {
1910 : return -GetLogicalUsedMargin(aWritingMode).BStart(aWritingMode);
1911 : }
1912 81 : // Otherwise, the bottom margin edge, per CSS2.1's definition of the
1913 0 : // 'baseline' value of 'vertical-align'.
1914 : return BSize(aWritingMode) +
1915 : GetLogicalUsedMargin(aWritingMode).BEnd(aWritingMode);
1916 : }
1917 612 :
1918 : const nsFrameList&
1919 0 : nsFrame::GetChildList(ChildListID aListID) const
1920 16 : {
1921 32 : if (IsAbsoluteContainer() &&
1922 : aListID == GetAbsoluteListID()) {
1923 : return GetAbsoluteContainingBlock()->GetChildList();
1924 : } else {
1925 : return nsFrameList::EmptyList();
1926 : }
1927 : }
1928 8014 :
1929 : void
1930 16028 : nsFrame::GetChildLists(nsTArray<ChildList>* aLists) const
1931 1340 : {
1932 670 : if (IsAbsoluteContainer()) {
1933 : nsFrameList absoluteList = GetAbsoluteContainingBlock()->GetChildList();
1934 0 : absoluteList.AppendIfNonempty(aLists, GetAbsoluteListID());
1935 : }
1936 : }
1937 0 :
1938 : void
1939 592 : nsIFrame::GetCrossDocChildLists(nsTArray<ChildList>* aLists)
1940 0 : {
1941 : nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(this);
1942 2 : if (subdocumentFrame) {
1943 0 : // Descend into the subdocument
1944 0 : nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
1945 0 : if (root) {
1946 0 : aLists->AppendElement(nsIFrame::ChildList(
1947 : nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
1948 : nsIFrame::kPrincipalList));
1949 : }
1950 0 : }
1951 0 :
1952 : GetChildLists(aLists);
1953 : }
1954 48 :
1955 : Visibility
1956 0 : nsIFrame::GetVisibility() const
1957 : {
1958 : if (!(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED)) {
1959 : return Visibility::UNTRACKED;
1960 0 : }
1961 0 :
1962 : bool isSet = false;
1963 0 : uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
1964 :
1965 : MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
1966 : "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
1967 0 :
1968 : return visibleCount > 0
1969 : ? Visibility::APPROXIMATELY_VISIBLE
1970 : : Visibility::APPROXIMATELY_NONVISIBLE;
1971 : }
1972 0 :
1973 : void
1974 0 : nsIFrame::UpdateVisibilitySynchronously()
1975 0 : {
1976 0 : nsIPresShell* presShell = PresShell();
1977 : if (!presShell) {
1978 : return;
1979 0 : }
1980 0 :
1981 0 : if (presShell->AssumeAllFramesVisible()) {
1982 : presShell->EnsureFrameInApproximatelyVisibleList(this);
1983 : return;
1984 0 : }
1985 0 :
1986 0 : bool visible = StyleVisibility()->IsVisible();
1987 0 : nsIFrame* f = GetParent();
1988 0 : nsRect rect = GetRectRelativeToSelf();
1989 0 : nsIFrame* rectFrame = this;
1990 0 : while (f && visible) {
1991 : nsIScrollableFrame* sf = do_QueryFrame(f);
1992 0 : if (sf) {
1993 0 : nsRect transformedRect =
1994 0 : nsLayoutUtils::TransformFrameRectToAncestor(rectFrame, rect, f);
1995 0 : if (!sf->IsRectNearlyVisible(transformedRect)) {
1996 : visible = false;
1997 : break;
1998 : }
1999 :
2000 : // In this code we're trying to synchronously update *approximate*
2001 : // visibility. (In the future we may update precise visibility here as
2002 : // well, which is why the method name does not contain 'approximate'.) The
2003 : // IsRectNearlyVisible() check above tells us that the rect we're checking
2004 : // is approximately visible within the scrollframe, but we still need to
2005 : // ensure that, even if it was scrolled into view, it'd be visible when we
2006 : // consider the rest of the document. To do that, we move transformedRect
2007 0 : // to be contained in the scrollport as best we can (it might not fit) to
2008 0 : // pretend that it was scrolled into view.
2009 : rect = transformedRect.MoveInsideAndClamp(sf->GetScrollPortRect());
2010 0 : rectFrame = f;
2011 0 : }
2012 0 : nsIFrame* parent = f->GetParent();
2013 0 : if (!parent) {
2014 : parent = nsLayoutUtils::GetCrossDocParentFrame(f);
2015 : if (parent && parent->PresContext()->IsChrome()) {
2016 : break;
2017 : }
2018 : }
2019 : f = parent;
2020 0 : }
2021 0 :
2022 : if (visible) {
2023 0 : presShell->EnsureFrameInApproximatelyVisibleList(this);
2024 : } else {
2025 : presShell->RemoveFrameFromApproximatelyVisibleList(this);
2026 : }
2027 : }
2028 0 :
2029 : void
2030 0 : nsIFrame::EnableVisibilityTracking()
2031 : {
2032 : if (GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED) {
2033 : return; // Nothing to do.
2034 0 : }
2035 :
2036 : MOZ_ASSERT(!HasProperty(VisibilityStateProperty()),
2037 : "Shouldn't have a VisibilityStateProperty value "
2038 : "if NS_FRAME_VISIBILITY_IS_TRACKED is not set");
2039 :
2040 0 : // Add the state bit so we know to track visibility for this frame, and
2041 0 : // initialize the frame property.
2042 : AddStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
2043 0 : SetProperty(VisibilityStateProperty(), 0);
2044 0 :
2045 : nsIPresShell* presShell = PresShell();
2046 : if (!presShell) {
2047 : return;
2048 : }
2049 :
2050 : // Schedule a visibility update. This method will virtually always be called
2051 : // when layout has changed anyway, so it's very unlikely that any additional
2052 0 : // visibility updates will be triggered by this, but this way we guarantee
2053 : // that if this frame is currently visible we'll eventually find out.
2054 : presShell->ScheduleApproximateFrameVisibilityUpdateSoon();
2055 : }
2056 48 :
2057 : void
2058 0 : nsIFrame::DisableVisibilityTracking()
2059 48 : {
2060 : if (!(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED)) {
2061 : return; // Nothing to do.
2062 0 : }
2063 0 :
2064 : bool isSet = false;
2065 0 : uint32_t visibleCount = RemoveProperty(VisibilityStateProperty(), &isSet);
2066 :
2067 : MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
2068 0 : "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
2069 :
2070 0 : RemoveStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
2071 :
2072 : if (visibleCount == 0) {
2073 : return; // We were nonvisible.
2074 : }
2075 0 :
2076 : // We were visible, so send an OnVisibilityChange() notification.
2077 : OnVisibilityChange(Visibility::APPROXIMATELY_NONVISIBLE);
2078 : }
2079 0 :
2080 : void
2081 : nsIFrame::DecApproximateVisibleCount(const Maybe<OnNonvisible>& aNonvisibleAction
2082 0 : /* = Nothing() */)
2083 : {
2084 0 : MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
2085 0 :
2086 : bool isSet = false;
2087 0 : uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
2088 :
2089 0 : MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
2090 : "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
2091 : MOZ_ASSERT(visibleCount > 0, "Frame is already nonvisible and we're "
2092 0 : "decrementing its visible count?");
2093 0 :
2094 0 : visibleCount--;
2095 0 : SetProperty(VisibilityStateProperty(), visibleCount);
2096 : if (visibleCount > 0) {
2097 : return;
2098 : }
2099 0 :
2100 : // We just became nonvisible, so send an OnVisibilityChange() notification.
2101 : OnVisibilityChange(Visibility::APPROXIMATELY_NONVISIBLE, aNonvisibleAction);
2102 : }
2103 0 :
2104 : void
2105 0 : nsIFrame::IncApproximateVisibleCount()
2106 : {
2107 0 : MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
2108 0 :
2109 : bool isSet = false;
2110 0 : uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
2111 :
2112 : MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
2113 0 : "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
2114 0 :
2115 0 : visibleCount++;
2116 0 : SetProperty(VisibilityStateProperty(), visibleCount);
2117 : if (visibleCount > 1) {
2118 : return;
2119 : }
2120 0 :
2121 : // We just became visible, so send an OnVisibilityChange() notification.
2122 : OnVisibilityChange(Visibility::APPROXIMATELY_VISIBLE);
2123 : }
2124 0 :
2125 : void
2126 : nsIFrame::OnVisibilityChange(Visibility aNewVisibility,
2127 : const Maybe<OnNonvisible>& aNonvisibleAction
2128 : /* = Nothing() */)
2129 : {
2130 0 : // XXX(seth): In bug 1218990 we'll implement visibility tracking for CSS
2131 : // images here.
2132 : }
2133 0 :
2134 : static nsIFrame*
2135 0 : GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
2136 0 : {
2137 0 : nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
2138 0 : if (capturingContent) {
2139 : nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
2140 : return activeFrame ? activeFrame : aFrame;
2141 : }
2142 :
2143 : return aFrame;
2144 : }
2145 0 :
2146 : int16_t
2147 0 : nsFrame::DisplaySelection(nsPresContext* aPresContext, bool isOkToTurnOn)
2148 : {
2149 0 : int16_t selType = nsISelectionController::SELECTION_OFF;
2150 0 :
2151 0 : nsCOMPtr<nsISelectionController> selCon;
2152 0 : nsresult result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
2153 0 : if (NS_SUCCEEDED(result) && selCon) {
2154 : result = selCon->GetDisplaySelection(&selType);
2155 0 : if (NS_SUCCEEDED(result) && (selType != nsISelectionController::SELECTION_OFF)) {
2156 0 : // Check whether style allows selection.
2157 0 : if (!IsSelectable(nullptr)) {
2158 : selType = nsISelectionController::SELECTION_OFF;
2159 : isOkToTurnOn = false;
2160 0 : }
2161 0 : }
2162 0 : if (isOkToTurnOn && (selType == nsISelectionController::SELECTION_OFF)) {
2163 : selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
2164 : selType = nsISelectionController::SELECTION_ON;
2165 0 : }
2166 : }
2167 : return selType;
2168 : }
2169 :
2170 0 : class nsDisplaySelectionOverlay : public nsDisplayItem {
2171 : public:
2172 0 : nsDisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
2173 0 : nsFrame* aFrame, int16_t aSelectionValue)
2174 0 : : nsDisplayItem(aBuilder, aFrame), mSelectionValue(aSelectionValue) {
2175 : MOZ_COUNT_CTOR(nsDisplaySelectionOverlay);
2176 0 : }
2177 0 : #ifdef NS_BUILD_REFCNT_LOGGING
2178 0 : virtual ~nsDisplaySelectionOverlay() {
2179 : MOZ_COUNT_DTOR(nsDisplaySelectionOverlay);
2180 : }
2181 : #endif
2182 :
2183 : virtual void Paint(nsDisplayListBuilder* aBuilder,
2184 : gfxContext* aCtx) override;
2185 : bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
2186 : mozilla::wr::IpcResourceUpdateQueue& aResources,
2187 : const StackingContextHelper& aSc,
2188 0 : mozilla::layers::WebRenderLayerManager* aManager,
2189 : nsDisplayListBuilder* aDisplayListBuilder) override;
2190 : NS_DISPLAY_DECL_NAME("SelectionOverlay", TYPE_SELECTION_OVERLAY)
2191 : private:
2192 : Color ComputeColor() const;
2193 :
2194 : static Color ComputeColorFromSelectionStyle(ComputedStyle&);
2195 : static Color ApplyTransparencyIfNecessary(nscolor);
2196 :
2197 : int16_t mSelectionValue;
2198 : };
2199 0 :
2200 : Color
2201 : nsDisplaySelectionOverlay::ApplyTransparencyIfNecessary(nscolor aColor)
2202 0 : {
2203 0 : // If it has already alpha, leave it like that.
2204 : if (NS_GET_A(aColor) != 255) {
2205 : return ToDeviceColor(aColor);
2206 : }
2207 :
2208 0 : // NOTE(emilio): Blink and WebKit do something slightly different here, and
2209 0 : // blend the color with white instead, both for overlays and text backgrounds.
2210 0 : auto color = Color::FromABGR(aColor);
2211 : color.a = 0.5;
2212 : return ToDeviceColor(color);
2213 : }
2214 0 :
2215 : Color
2216 : nsDisplaySelectionOverlay::ComputeColorFromSelectionStyle(ComputedStyle& aStyle)
2217 0 : {
2218 : return ApplyTransparencyIfNecessary(
2219 : aStyle.GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor));
2220 : }
2221 0 :
2222 : Color
2223 : nsDisplaySelectionOverlay::ComputeColor() const
2224 0 : {
2225 0 : LookAndFeel::ColorID colorID;
2226 0 : if (mSelectionValue == nsISelectionController::SELECTION_ON) {
2227 : if (RefPtr<ComputedStyle> style = mFrame->ComputeSelectionStyle()) {
2228 0 : return ComputeColorFromSelectionStyle(*style);
2229 0 : }
2230 : colorID = LookAndFeel::eColorID_TextSelectBackground;
2231 : } else if (mSelectionValue == nsISelectionController::SELECTION_ATTENTION) {
2232 0 : colorID = LookAndFeel::eColorID_TextSelectBackgroundAttention;
2233 : } else {
2234 : colorID = LookAndFeel::eColorID_TextSelectBackgroundDisabled;
2235 : }
2236 0 :
2237 : return ApplyTransparencyIfNecessary(
2238 : LookAndFeel::GetColor(colorID, NS_RGB(255, 255, 255)));
2239 0 : }
2240 :
2241 : void nsDisplaySelectionOverlay::Paint(nsDisplayListBuilder* aBuilder,
2242 0 : gfxContext* aCtx)
2243 0 : {
2244 : DrawTarget& aDrawTarget = *aCtx->GetDrawTarget();
2245 : ColorPattern color(ComputeColor());
2246 0 :
2247 0 : nsIntRect pxRect =
2248 0 : GetPaintRect().ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
2249 : Rect rect(pxRect.x, pxRect.y, pxRect.width, pxRect.height);
2250 0 : MaybeSnapToDevicePixels(rect, aDrawTarget, true);
2251 0 :
2252 : aDrawTarget.FillRect(rect, color);
2253 : }
2254 :
2255 0 :
2256 : bool
2257 : nsDisplaySelectionOverlay::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
2258 : mozilla::wr::IpcResourceUpdateQueue& aResources,
2259 : const StackingContextHelper& aSc,
2260 : mozilla::layers::WebRenderLayerManager* aManager,
2261 : nsDisplayListBuilder* aDisplayListBuilder)
2262 0 : {
2263 0 : wr::LayoutRect bounds = wr::ToRoundedLayoutRect(
2264 0 : LayoutDeviceRect::FromAppUnits(nsRect(ToReferenceFrame(), Frame()->GetSize()),
2265 0 : mFrame->PresContext()->AppUnitsPerDevPixel()));
2266 0 : aBuilder.PushRect(bounds, bounds, !BackfaceIsHidden(),
2267 : wr::ToColorF(ComputeColor()));
2268 : return true;
2269 : }
2270 0 :
2271 : static Element*
2272 0 : FindElementAncestorForMozSelection(nsIContent* aContent)
2273 0 : {
2274 0 : NS_ENSURE_TRUE(aContent, nullptr);
2275 : while (aContent && aContent->IsInNativeAnonymousSubtree()) {
2276 0 : aContent = aContent->GetBindingParent();
2277 0 : }
2278 0 : NS_ASSERTION(aContent, "aContent isn't in non-anonymous tree?");
2279 : while (aContent && !aContent->IsElement()) {
2280 0 : aContent = aContent->GetParent();
2281 : }
2282 : return aContent ? aContent->AsElement() : nullptr;
2283 : }
2284 :
2285 0 :
2286 : already_AddRefed<ComputedStyle>
2287 0 : nsIFrame::ComputeSelectionStyle() const
2288 0 : {
2289 : Element* element = FindElementAncestorForMozSelection(GetContent());
2290 : if (!element) {
2291 : return nullptr;
2292 0 : }
2293 0 : RefPtr<ComputedStyle> sc =
2294 0 : PresContext()->StyleSet()->ProbePseudoElementStyle(
2295 : element, CSSPseudoElementType::selection, Style());
2296 : return sc.forget();
2297 : }
2298 :
2299 : /********************************************************
2300 : * Refreshes each content's frame
2301 : *********************************************************/
2302 384 :
2303 : void
2304 : nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
2305 : nsDisplayList* aList,
2306 384 : uint16_t aContentType)
2307 384 : {
2308 : if (!IsSelected() || !IsVisibleForPainting(aBuilder)) {
2309 : return;
2310 0 : }
2311 0 :
2312 : int16_t displaySelection = PresShell()->GetSelectionFlags();
2313 : if (!(displaySelection & aContentType)) {
2314 : return;
2315 0 : }
2316 0 :
2317 : const nsFrameSelection* frameSelection = GetConstFrameSelection();
2318 0 : int16_t selectionValue = frameSelection->GetDisplaySelection();
2319 :
2320 : if (selectionValue <= nsISelectionController::SELECTION_HIDDEN) {
2321 : return; // selection is hidden or off
2322 0 : }
2323 :
2324 : nsIContent* newContent = mContent->GetParent();
2325 0 :
2326 0 : //check to see if we are anonymous content
2327 : int32_t offset = 0;
2328 0 : if (newContent) {
2329 : // XXXbz there has GOT to be a better way of determining this!
2330 : offset = newContent->ComputeIndexOf(mContent);
2331 : }
2332 :
2333 0 : //look up to see what selection(s) are on this frame
2334 0 : UniquePtr<SelectionDetails> details =
2335 0 : frameSelection->LookUpSelection(newContent, offset, 1, false);
2336 : if (!details)
2337 : return;
2338 0 :
2339 0 : bool normal = false;
2340 0 : for (SelectionDetails* sd = details.get(); sd; sd = sd->mNext.get()) {
2341 : if (sd->mSelectionType == SelectionType::eNormal) {
2342 : normal = true;
2343 : }
2344 0 : }
2345 :
2346 : if (!normal && aContentType == nsISelectionDisplay::DISPLAY_IMAGES) {
2347 : // Don't overlay an image if it's not in the primary selection.
2348 : return;
2349 : }
2350 0 :
2351 : aList->AppendToTop(
2352 : MakeDisplayItem<nsDisplaySelectionOverlay>(aBuilder, this, selectionValue));
2353 : }
2354 623 :
2355 : void
2356 : nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
2357 623 : const nsDisplayListSet& aLists)
2358 : {
2359 : if (!StyleOutline()->ShouldPaintOutline()) {
2360 : return;
2361 0 : }
2362 0 :
2363 : aLists.Outlines()->AppendToTop(
2364 : MakeDisplayItem<nsDisplayOutline>(aBuilder, this));
2365 : }
2366 13 :
2367 : void
2368 : nsFrame::DisplayOutline(nsDisplayListBuilder* aBuilder,
2369 13 : const nsDisplayListSet& aLists)
2370 : {
2371 : if (!IsVisibleForPainting(aBuilder))
2372 0 : return;
2373 :
2374 : DisplayOutlineUnconditional(aBuilder, aLists);
2375 : }
2376 5 :
2377 : void
2378 : nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
2379 5 : nsDisplayList* aList)
2380 : {
2381 : if (!IsVisibleForPainting(aBuilder))
2382 0 : return;
2383 :
2384 : aList->AppendToTop(MakeDisplayItem<nsDisplayCaret>(aBuilder, this));
2385 : }
2386 2 :
2387 : nscolor
2388 0 : nsIFrame::GetCaretColorAt(int32_t aOffset)
2389 : {
2390 : return nsLayoutUtils::GetColor(this, &nsStyleUserInterface::mCaretColor);
2391 : }
2392 0 :
2393 : bool
2394 : nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
2395 : const nsDisplayListSet& aLists,
2396 : bool aForceBackground)
2397 : {
2398 : // Here we don't try to detect background propagation. Frames that might
2399 2432 : // receive a propagated background should just set aForceBackground to
2400 1758 : // true.
2401 144 : if (aBuilder->IsForEventDelivery() || aForceBackground ||
2402 72 : !StyleBackground()->IsTransparent(this) || StyleDisplay()->mAppearance) {
2403 : return nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
2404 : aBuilder, this, GetRectRelativeToSelf(), aLists.BorderBackground());
2405 : }
2406 : return false;
2407 : }
2408 0 :
2409 : void
2410 : nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
2411 : const nsDisplayListSet& aLists,
2412 : bool aForceBackground)
2413 : {
2414 : // The visibility check belongs here since child elements have the
2415 610 : // opportunity to override the visibility property and display even if
2416 : // their parent is hidden.
2417 : if (!IsVisibleForPainting(aBuilder)) {
2418 : return;
2419 1220 : }
2420 610 :
2421 0 : nsCSSShadowArray* shadows = StyleEffects()->mBoxShadow;
2422 32 : if (shadows && shadows->HasShadowWithInset(false)) {
2423 : aLists.BorderBackground()->AppendToTop(
2424 : MakeDisplayItem<nsDisplayBoxShadowOuter>(aBuilder, this));
2425 0 : }
2426 0 :
2427 : bool bgIsThemed = DisplayBackgroundUnconditional(aBuilder, aLists,
2428 0 : aForceBackground);
2429 0 :
2430 0 : if (shadows && shadows->HasShadowWithInset(true)) {
2431 : aLists.BorderBackground()->AppendToTop(
2432 : MakeDisplayItem<nsDisplayBoxShadowInner>(aBuilder, this));
2433 : }
2434 :
2435 0 : // If there's a themed background, we should not create a border item.
2436 0 : // It won't be rendered.
2437 96 : if (!bgIsThemed && StyleBorder()->HasBorder()) {
2438 : aLists.BorderBackground()->AppendToTop(
2439 : MakeDisplayItem<nsDisplayBorder>(aBuilder, this));
2440 610 : }
2441 :
2442 : DisplayOutlineUnconditional(aBuilder, aLists);
2443 0 : }
2444 :
2445 : inline static bool IsSVGContentWithCSSClip(const nsIFrame *aFrame)
2446 : {
2447 : // The CSS spec says that the 'clip' property only applies to absolutely
2448 : // positioned elements, whereas the SVG spec says that it applies to SVG
2449 : // elements regardless of the value of the 'position' property. Here we obey
2450 0 : // the CSS spec for outer-<svg> (since that's what we generally do), but
2451 0 : // obey the SVG spec for other SVG elements to which 'clip' applies.
2452 0 : return (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
2453 : aFrame->GetContent()->IsAnyOfSVGElements(nsGkAtoms::svg,
2454 : nsGkAtoms::foreignObject);
2455 : }
2456 0 :
2457 : Maybe<nsRect>
2458 : nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp,
2459 : const nsStyleEffects* aEffects,
2460 2092 : const nsSize& aSize) const
2461 0 : {
2462 : if (!(aEffects->mClipFlags & NS_STYLE_CLIP_RECT) ||
2463 : !(aDisp->IsAbsolutelyPositioned(this) || IsSVGContentWithCSSClip(this))) {
2464 : return Nothing();
2465 0 : }
2466 0 :
2467 : nsRect rect = aEffects->mClip;
2468 : if (MOZ_LIKELY(StyleBorder()->mBoxDecorationBreak ==
2469 : StyleBoxDecorationBreak::Slice)) {
2470 0 : // The clip applies to the joined boxes so it's relative the first
2471 0 : // continuation.
2472 0 : nscoord y = 0;
2473 : for (nsIFrame* f = GetPrevContinuation(); f; f = f->GetPrevContinuation()) {
2474 0 : y += f->GetRect().height;
2475 : }
2476 : rect.MoveBy(nsPoint(0, -y));
2477 0 : }
2478 0 :
2479 : if (NS_STYLE_CLIP_RIGHT_AUTO & aEffects->mClipFlags) {
2480 0 : rect.width = aSize.width - rect.x;
2481 0 : }
2482 : if (NS_STYLE_CLIP_BOTTOM_AUTO & aEffects->mClipFlags) {
2483 0 : rect.height = aSize.height - rect.y;
2484 : }
2485 : return Some(rect);
2486 : }
2487 :
2488 : /**
2489 : * If the CSS 'overflow' property applies to this frame, and is not
2490 : * handled by constructing a dedicated nsHTML/XULScrollFrame, set up clipping
2491 : * for that overflow in aBuilder->ClipState() to clip all containing-block
2492 : * descendants.
2493 : *
2494 : * Return true if clipping was applied.
2495 323 : */
2496 : static bool
2497 : ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
2498 : const nsIFrame* aFrame,
2499 : const nsStyleDisplay* aDisp,
2500 : DisplayListClipState::AutoClipMultiple& aClipState)
2501 : {
2502 : // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
2503 : // frames, and any non-visible value for blocks in a paginated context).
2504 : // We allow -moz-hidden-unscrollable to apply to any kind of frame. This
2505 323 : // is required by comboboxes which make their display text (an inline frame)
2506 : // have clipping.
2507 : if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) {
2508 64 : return false;
2509 32 : }
2510 : nsRect clipRect;
2511 0 : bool haveRadii = false;
2512 : nscoord radii[8];
2513 32 : auto* disp = aFrame->StyleDisplay();
2514 0 : // Only deflate the padding if we clip to the content-box in that axis.
2515 0 : auto wm = aFrame->GetWritingMode();
2516 32 : bool cbH = (wm.IsVertical() ? disp->mOverflowClipBoxBlock
2517 0 : : disp->mOverflowClipBoxInline) ==
2518 0 : NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
2519 32 : bool cbV = (wm.IsVertical() ? disp->mOverflowClipBoxInline
2520 0 : : disp->mOverflowClipBoxBlock) ==
2521 0 : NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX;
2522 0 : nsMargin bp = aFrame->GetUsedPadding();
2523 : if (!cbH) {
2524 32 : bp.left = bp.right = nscoord(0);
2525 0 : }
2526 : if (!cbV) {
2527 : bp.top = bp.bottom = nscoord(0);
2528 0 : }
2529 0 :
2530 0 : bp += aFrame->GetUsedBorder();
2531 0 : bp.ApplySkipSides(aFrame->GetSkipSides());
2532 0 : nsRect rect(nsPoint(0, 0), aFrame->GetSize());
2533 0 : rect.Deflate(bp);
2534 1 : clipRect = rect + aBuilder->ToReferenceFrame(aFrame);
2535 : haveRadii = aFrame->GetBoxBorderRadii(radii, bp, false);
2536 : aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr);
2537 : return true;
2538 : }
2539 0 :
2540 : #ifdef DEBUG
2541 : static void PaintDebugBorder(nsIFrame* aFrame, DrawTarget* aDrawTarget,
2542 0 : const nsRect& aDirtyRect, nsPoint aPt)
2543 0 : {
2544 0 : nsRect r(aPt, aFrame->GetSize());
2545 0 : int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
2546 0 : Color blueOrRed(aFrame->HasView() ? Color(0.f, 0.f, 1.f, 1.f) :
2547 0 : Color(1.f, 0.f, 0.f, 1.f));
2548 0 : aDrawTarget->StrokeRect(NSRectToRect(r, appUnitsPerDevPixel),
2549 : ColorPattern(ToDeviceColor(blueOrRed)));
2550 0 : }
2551 :
2552 : static void PaintEventTargetBorder(nsIFrame* aFrame, DrawTarget* aDrawTarget,
2553 0 : const nsRect& aDirtyRect, nsPoint aPt)
2554 0 : {
2555 0 : nsRect r(aPt, aFrame->GetSize());
2556 0 : int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
2557 0 : ColorPattern purple(ToDeviceColor(Color(.5f, 0.f, .5f, 1.f)));
2558 : aDrawTarget->StrokeRect(NSRectToRect(r, appUnitsPerDevPixel), purple);
2559 : }
2560 1 :
2561 : static void
2562 : DisplayDebugBorders(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
2563 : const nsDisplayListSet& aLists) {
2564 688 : // Draw a border around the child
2565 0 : // REVIEW: From nsContainerFrame::PaintChild
2566 0 : if (nsFrame::GetShowFrameBorders() && !aFrame->GetRect().IsEmpty()) {
2567 0 : aLists.Outlines()->AppendToTop(
2568 : MakeDisplayItem<nsDisplayGeneric>(aBuilder, aFrame, PaintDebugBorder, "DebugBorder",
2569 : DisplayItemType::TYPE_DEBUG_BORDER));
2570 1 : }
2571 0 : // Draw a border around the current event target
2572 0 : if (nsFrame::GetShowEventTargetFrameBorder() &&
2573 0 : aFrame->PresShell()->GetDrawEventTargetFrame() == aFrame) {
2574 0 : aLists.Outlines()->AppendToTop(
2575 : MakeDisplayItem<nsDisplayGeneric>(aBuilder, aFrame, PaintEventTargetBorder, "EventTargetBorder",
2576 688 : DisplayItemType::TYPE_EVENT_TARGET_BORDER));
2577 : }
2578 : }
2579 : #endif
2580 0 :
2581 : static bool
2582 0 : IsScrollFrameActive(nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
2583 : {
2584 : return aScrollableFrame && aScrollableFrame->IsScrollingActive(aBuilder);
2585 : }
2586 :
2587 : /**
2588 : * Returns whether a display item that gets created with the builder's current
2589 : * state will have a scrolled clip, i.e. a clip that is scrolled by a scroll
2590 : * frame which does not move the item itself.
2591 0 : */
2592 : static bool
2593 : BuilderHasScrolledClip(nsDisplayListBuilder* aBuilder)
2594 0 : {
2595 0 : const DisplayItemClipChain* currentClip =
2596 : aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder);
2597 : if (!currentClip) {
2598 : return false;
2599 0 : }
2600 0 :
2601 0 : const ActiveScrolledRoot* currentClipASR = currentClip->mASR;
2602 : const ActiveScrolledRoot* currentASR = aBuilder->CurrentActiveScrolledRoot();
2603 : return ActiveScrolledRoot::PickDescendant(currentClipASR, currentASR) != currentASR;
2604 : }
2605 :
2606 : class AutoSaveRestoreContainsBlendMode
2607 : {
2608 : nsDisplayListBuilder& mBuilder;
2609 : bool mSavedContainsBlendMode;
2610 : public:
2611 110 : explicit AutoSaveRestoreContainsBlendMode(nsDisplayListBuilder& aBuilder)
2612 : : mBuilder(aBuilder)
2613 : , mSavedContainsBlendMode(aBuilder.ContainsBlendMode())
2614 : { }
2615 220 :
2616 : ~AutoSaveRestoreContainsBlendMode() {
2617 : mBuilder.SetContainsBlendMode(mSavedContainsBlendMode);
2618 : }
2619 : };
2620 795 :
2621 : static void
2622 795 : CheckForApzAwareEventHandlers(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
2623 : {
2624 : if (aBuilder->GetAncestorHasApzAwareEventHandler()) {
2625 : return;
2626 607 : }
2627 607 :
2628 : nsIContent* content = aFrame->GetContent();
2629 : if (!content) {
2630 : return;
2631 588 : }
2632 :
2633 : if (content->IsNodeApzAware()) {
2634 : aBuilder->SetAncestorHasApzAwareEventHandler(true);
2635 : }
2636 : }
2637 :
2638 : /**
2639 : * True if aDescendant participates the context aAncestor participating.
2640 0 : */
2641 0 : static bool
2642 0 : FrameParticipatesIn3DContext(nsIFrame* aAncestor, nsIFrame* aDescendant) {
2643 : MOZ_ASSERT(aAncestor != aDescendant);
2644 0 : MOZ_ASSERT(aAncestor->Extend3DContext());
2645 0 : nsIFrame* frame;
2646 : for (frame = aDescendant->GetInFlowParent();
2647 0 : frame && aAncestor != frame;
2648 : frame = frame->GetInFlowParent()) {
2649 : if (!frame->Extend3DContext()) {
2650 : return false;
2651 0 : }
2652 : }
2653 : MOZ_ASSERT(frame == aAncestor);
2654 : return true;
2655 : }
2656 0 :
2657 : static bool
2658 : ItemParticipatesIn3DContext(nsIFrame* aAncestor, nsDisplayItem* aItem)
2659 0 : {
2660 0 : nsIFrame* transformFrame;
2661 0 : if (aItem->GetType() == DisplayItemType::TYPE_TRANSFORM ||
2662 : aItem->GetType() == DisplayItemType::TYPE_PERSPECTIVE) {
2663 : transformFrame = aItem->Frame();
2664 : } else {
2665 0 : return false;
2666 : }
2667 : if (aAncestor == transformFrame) {
2668 0 : return true;
2669 : }
2670 : return FrameParticipatesIn3DContext(aAncestor, transformFrame);
2671 : }
2672 0 :
2673 : static void
2674 : WrapSeparatorTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
2675 0 : nsDisplayList* aSource, nsDisplayList* aTarget,
2676 : int aIndex) {
2677 0 : if (!aSource->IsEmpty()) {
2678 0 : nsDisplayTransform *sepIdItem =
2679 0 : MakeDisplayItem<nsDisplayTransform>(aBuilder, aFrame, aSource,
2680 0 : aBuilder->GetVisibleRect(), Matrix4x4(), aIndex);
2681 : sepIdItem->SetNoExtendContext();
2682 0 : aTarget->AppendToTop(sepIdItem);
2683 : }
2684 : }
2685 :
2686 : // Try to compute a clip rect to bound the contents of the mask item
2687 : // that will be built for |aMaskedFrame|. If we're not able to compute
2688 : // one, return an empty Maybe.
2689 0 : // The returned clip rect, if there is one, is relative to |aMaskedFrame|.
2690 : static Maybe<nsRect>
2691 : ComputeClipForMaskItem(nsDisplayListBuilder* aBuilder, nsIFrame* aMaskedFrame,
2692 0 : bool aHandleOpacity)
2693 : {
2694 0 : const nsStyleSVGReset* svgReset = aMaskedFrame->StyleSVGReset();
2695 0 :
2696 : nsSVGUtils::MaskUsage maskUsage;
2697 0 : nsSVGUtils::DetermineMaskUsage(aMaskedFrame, aHandleOpacity, maskUsage);
2698 0 :
2699 : nsPoint offsetToUserSpace = nsLayoutUtils::ComputeOffsetToUserSpace(aBuilder, aMaskedFrame);
2700 0 : int32_t devPixelRatio = aMaskedFrame->PresContext()->AppUnitsPerDevPixel();
2701 0 : gfxPoint devPixelOffsetToUserSpace = nsLayoutUtils::PointToGfxPoint(
2702 : offsetToUserSpace, devPixelRatio);
2703 0 : gfxMatrix cssToDevMatrix = nsSVGUtils::GetCSSPxToDevPxMatrix(aMaskedFrame);
2704 0 :
2705 : nsPoint toReferenceFrame;
2706 0 : aBuilder->FindReferenceFrameFor(aMaskedFrame, &toReferenceFrame);
2707 0 :
2708 : Maybe<gfxRect> combinedClip;
2709 0 : if (maskUsage.shouldApplyBasicShape) {
2710 0 : Rect result = nsCSSClipPathInstance::GetBoundingRectForBasicShapeClip(
2711 0 : aMaskedFrame, svgReset->mClipPath);
2712 : combinedClip = Some(ThebesRect(result));
2713 : } else if (maskUsage.shouldApplyClipPath) {
2714 : gfxRect result = nsSVGUtils::GetBBox(aMaskedFrame,
2715 : nsSVGUtils::eBBoxIncludeClipped |
2716 : nsSVGUtils::eBBoxIncludeFill |
2717 0 : nsSVGUtils::eBBoxIncludeMarkers |
2718 0 : nsSVGUtils::eBBoxIncludeStroke |
2719 : nsSVGUtils::eDoNotClipToBBoxOfContentInsideClipPath);
2720 : combinedClip = Some(cssToDevMatrix.TransformBounds(result));
2721 : } else {
2722 0 : // The code for this case is adapted from ComputeMaskGeometry().
2723 0 :
2724 : nsRect borderArea(toReferenceFrame, aMaskedFrame->GetSize());
2725 : borderArea -= offsetToUserSpace;
2726 :
2727 : // Use an infinite dirty rect to pass into nsCSSRendering::
2728 : // GetImageLayerClip() because we don't have an actual dirty rect to
2729 : // pass in. This is fine because the only time GetImageLayerClip() will
2730 0 : // not intersect the incoming dirty rect with something is in the "NoClip"
2731 : // case, and we handle that specially.
2732 0 : nsRect dirtyRect(nscoord_MIN/2, nscoord_MIN/2, nscoord_MAX, nscoord_MAX);
2733 :
2734 0 : nsIFrame* firstFrame = nsLayoutUtils::FirstContinuationOrIBSplitSibling(aMaskedFrame);
2735 0 : SVGObserverUtils::EffectProperties effectProperties =
2736 : SVGObserverUtils::GetEffectProperties(firstFrame);
2737 0 : nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
2738 0 :
2739 0 : for (uint32_t i = 0; i < maskFrames.Length(); ++i) {
2740 0 : gfxRect clipArea;
2741 0 : if (maskFrames[i]) {
2742 : clipArea = maskFrames[i]->GetMaskArea(aMaskedFrame);
2743 0 : clipArea = cssToDevMatrix.TransformBounds(clipArea);
2744 0 : } else {
2745 0 : const auto& layer = svgReset->mMask.mLayers[i];
2746 : if (layer.mClip == StyleGeometryBox::NoClip) {
2747 : return Nothing();
2748 0 : }
2749 :
2750 0 : nsCSSRendering::ImageLayerClipState clipState;
2751 : nsCSSRendering::GetImageLayerClip(layer, aMaskedFrame,
2752 : *aMaskedFrame->StyleBorder(),
2753 0 : borderArea, dirtyRect,
2754 0 : false /* aWillPaintBorder */,
2755 : devPixelRatio, &clipState);
2756 0 : clipArea = clipState.mDirtyRectInDevPx;
2757 : }
2758 : combinedClip = UnionMaybeRects(combinedClip, Some(clipArea));
2759 0 : }
2760 0 : }
2761 : if (combinedClip) {
2762 : if (combinedClip->IsEmpty()) {
2763 : // *clipForMask might be empty if all mask references are not resolvable
2764 : // or the size of them are empty. We still need to create a transparent mask
2765 : // before bug 1276834 fixed, so don't clip ctx by an empty rectangle for for
2766 : // now.
2767 : return Nothing();
2768 : }
2769 0 :
2770 : // Convert to user space.
2771 : *combinedClip += devPixelOffsetToUserSpace;
2772 :
2773 : // Round the clip out. In FrameLayerBuilder we round clips to nearest
2774 : // pixels, and if we have a really thin clip here, that can cause the
2775 : // clip to become empty if we didn't round out here.
2776 0 : // The rounding happens in coordinates that are relative to the reference
2777 : // frame, which matches what FrameLayerBuilder does.
2778 : combinedClip->RoundOut();
2779 0 :
2780 : // Convert to app units.
2781 : nsRect result = nsLayoutUtils::RoundGfxRectToAppRect(*combinedClip, devPixelRatio);
2782 :
2783 0 : // The resulting clip is relative to the reference frame, but the caller
2784 0 : // expects it to be relative to the masked frame, so adjust it.
2785 : result -= toReferenceFrame;
2786 : return Some(result);
2787 : }
2788 : return Nothing();
2789 : }
2790 :
2791 1165 : struct AutoCheckBuilder {
2792 : explicit AutoCheckBuilder(nsDisplayListBuilder* aBuilder)
2793 1165 : : mBuilder(aBuilder)
2794 : {
2795 : aBuilder->Check();
2796 0 : }
2797 0 :
2798 2330 : ~AutoCheckBuilder()
2799 1165 : {
2800 : mBuilder->Check();
2801 : }
2802 :
2803 : nsDisplayListBuilder* mBuilder;
2804 : };
2805 126 :
2806 : void
2807 : nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
2808 362 : nsDisplayList* aList,
2809 0 : bool* aCreatedContainerItem) {
2810 0 : AutoCheckBuilder check(aBuilder);
2811 : if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
2812 : return;
2813 :
2814 126 : // Replaced elements have their visibility handled here, because
2815 : // they're visually atomic
2816 : if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
2817 126 : return;
2818 0 :
2819 126 : const nsStyleDisplay* disp = StyleDisplay();
2820 : const nsStyleEffects* effects = StyleEffects();
2821 : EffectSet* effectSet = EffectSet::GetEffectSet(this);
2822 : // We can stop right away if this is a zero-opacity stacking context and
2823 : // we're painting, and we're not animating opacity. Don't do this
2824 126 : // if we're going to compute plugin geometry, since opacity-0 plugins
2825 284 : // need to have display items built for them.
2826 158 : bool opacityItemForEventsAndPluginsOnly = false;
2827 0 : if (effects->mOpacity == 0.0 && aBuilder->IsForPainting() &&
2828 16 : !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
2829 0 : !nsLayoutUtils::HasAnimationOfProperty(effectSet, eCSSProperty_opacity)) {
2830 : if (aBuilder->WillComputePluginGeometry()) {
2831 : opacityItemForEventsAndPluginsOnly = true;
2832 : } else {
2833 : return;
2834 : }
2835 110 : }
2836 0 :
2837 : if (disp->mWillChangeBitField != 0) {
2838 : aBuilder->AddToWillChangeBudget(this, GetSize());
2839 : }
2840 :
2841 : // For preserves3d, use the dirty rect already installed on the
2842 0 : // builder, since aDirtyRect maybe distorted for transforms along
2843 0 : // the chain.
2844 : nsRect visibleRect = aBuilder->GetVisibleRect();
2845 0 : nsRect dirtyRect = aBuilder->GetDirtyRect();
2846 0 :
2847 0 : const bool isTransformed = IsTransformed(disp);
2848 : const bool hasPerspective = isTransformed && HasPerspective(disp);
2849 110 : const bool extend3DContext = Extend3DContext(disp, effectSet);
2850 : const bool combines3DTransformWithAncestors =
2851 220 : (extend3DContext || isTransformed) && Combines3DTransformWithAncestors(disp);
2852 110 :
2853 : Maybe<nsDisplayListBuilder::AutoPreserves3DContext> autoPreserves3DContext;
2854 : if (extend3DContext && !combines3DTransformWithAncestors) {
2855 0 : // Start a new preserves3d context to keep informations on
2856 : // nsDisplayListBuilder.
2857 : autoPreserves3DContext.emplace(aBuilder);
2858 0 : // Save dirty rect on the builder to avoid being distorted for
2859 : // multiple transforms along the chain.
2860 : aBuilder->SavePreserves3DRect();
2861 :
2862 0 : // We rebuild everything within preserve-3d and don't try
2863 0 : // to retain, so override the dirty rect now.
2864 0 : if (aBuilder->IsRetainingDisplayList()) {
2865 : dirtyRect = visibleRect;
2866 : aBuilder->SetDisablePartialUpdates(true);
2867 : }
2868 : }
2869 :
2870 : // reset blend mode so we can keep track if this stacking context needs have
2871 330 : // a nsDisplayBlendContainer. Set the blend mode back when the routine exits
2872 220 : // so we keep track if the parent stacking context needs a container too.
2873 : AutoSaveRestoreContainsBlendMode autoRestoreBlendMode(*aBuilder);
2874 220 : aBuilder->SetContainsBlendMode(false);
2875 110 :
2876 0 : nsRect visibleRectOutsideTransform = visibleRect;
2877 110 : bool allowAsyncAnimation = false;
2878 22 : bool inTransform = aBuilder->IsInTransform();
2879 : if (isTransformed) {
2880 0 : const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
2881 0 : nsDisplayTransform::PrerenderDecision decision =
2882 : nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this, &dirtyRect);
2883 0 : switch (decision) {
2884 0 : case nsDisplayTransform::FullPrerender:
2885 0 : allowAsyncAnimation = true;
2886 : visibleRect = dirtyRect;
2887 0 : break;
2888 0 : case nsDisplayTransform::PartialPrerender:
2889 : allowAsyncAnimation = true;
2890 : visibleRect = dirtyRect;
2891 : MOZ_FALLTHROUGH;
2892 0 : // fall through to the NoPrerender case
2893 0 : case nsDisplayTransform::NoPrerender:
2894 : if (overflow.IsEmpty() && !extend3DContext) {
2895 : return;
2896 : }
2897 :
2898 0 : // If we're in preserve-3d then grab the dirty rect that was given to the root
2899 0 : // and transform using the combined transform.
2900 : if (combines3DTransformWithAncestors) {
2901 : visibleRect = dirtyRect = aBuilder->GetPreserves3DRect();
2902 0 : }
2903 0 :
2904 : nsRect untransformedDirtyRect;
2905 1 : if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this,
2906 1 : &untransformedDirtyRect)) {
2907 : dirtyRect = untransformedDirtyRect;
2908 : nsDisplayTransform::UntransformRect(visibleRect, overflow, this, &visibleRect);
2909 0 : } else {
2910 : // This should only happen if the transform is singular, in which case nothing is visible anyway
2911 : dirtyRect.SetEmpty();
2912 : visibleRect.SetEmpty();
2913 11 : }
2914 99 : }
2915 : inTransform = true;
2916 : } else if (IsFixedPosContainingBlock()) {
2917 : // Restict the building area to the overflow rect for these frames, since
2918 0 : // RetainedDisplayListBuilder uses it to know if the size of the stacking
2919 0 : // context changed.
2920 : visibleRect.IntersectRect(visibleRect, GetVisualOverflowRect());
2921 : dirtyRect.IntersectRect(dirtyRect, GetVisualOverflowRect());
2922 110 : }
2923 :
2924 : bool hasOverrideDirtyRect = false;
2925 110 : // If we have an override dirty region, and neither us nor our ancestors are
2926 : // modified, then use it.
2927 0 : if (HasOverrideDirtyRegion() && !aBuilder->InInvalidSubtree() && !IsFrameModified()) {
2928 0 : nsDisplayListBuilder::DisplayListBuildingData* data =
2929 0 : GetProperty(nsDisplayListBuilder::DisplayListBuildingRect());
2930 0 : if (data) {
2931 : dirtyRect = data->mDirtyRect.Intersect(visibleRect);
2932 : hasOverrideDirtyRect = true;
2933 : }
2934 220 : }
2935 110 :
2936 0 : bool usingFilter = StyleEffects()->HasFilters();
2937 : bool usingMask = nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this);
2938 220 : bool usingSVGEffects = usingFilter || usingMask;
2939 220 :
2940 0 : nsRect visibleRectOutsideSVGEffects = visibleRect;
2941 0 : nsDisplayList hoistedScrollInfoItemsStorage;
2942 0 : if (usingSVGEffects) {
2943 0 : dirtyRect =
2944 0 : nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
2945 0 : visibleRect =
2946 : nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, visibleRect);
2947 : aBuilder->EnterSVGEffectsContents(&hoistedScrollInfoItemsStorage);
2948 : }
2949 :
2950 : // We build an opacity item if it's not going to be drawn by SVG content, or
2951 : // SVG effects. SVG effects won't handle the opacity if we want an active
2952 : // layer (for async animations), see
2953 : // nsSVGIntegrationsUtils::PaintMaskAndClipPath or
2954 : // nsSVGIntegrationsUtils::PaintFilter.
2955 : bool useOpacity = HasVisualOpacity(effectSet) &&
2956 0 : !nsSVGUtils::CanOptimizeOpacity(this) &&
2957 0 : (!usingSVGEffects || nsDisplayOpacity::NeedsActiveLayer(aBuilder, this));
2958 0 : bool useBlendMode = effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL;
2959 0 : bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY &&
2960 0 : IsScrollFrameActive(aBuilder,
2961 0 : nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
2962 0 : nsLayoutUtils::SCROLLABLE_SAME_DOC |
2963 : nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
2964 110 : bool useFixedPosition = disp->mPosition == NS_STYLE_POSITION_FIXED &&
2965 110 : (nsLayoutUtils::IsFixedPosFrameInDisplayPort(this) || BuilderHasScrolledClip(aBuilder));
2966 0 :
2967 : nsDisplayListBuilder::AutoBuildingDisplayList
2968 : buildingDisplayList(aBuilder, this, visibleRect, dirtyRect, true);
2969 220 :
2970 : // Depending on the effects that are applied to this frame, we can create
2971 : // multiple container display items and wrap them around our contents.
2972 : // This enum lists all the potential container display items, in the order
2973 : // outside to inside.
2974 : enum class ContainerItemType : uint8_t {
2975 : eNone = 0,
2976 : eOwnLayerIfNeeded,
2977 : eBlendMode,
2978 : eFixedPosition,
2979 : eOwnLayerForTransformWithRoundedClip,
2980 : ePerspective,
2981 : eTransform,
2982 : eSeparatorTransforms,
2983 : eOpacity,
2984 : eFilter,
2985 : eBlendContainer
2986 : };
2987 :
2988 : nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
2989 220 :
2990 : DisplayListClipState::AutoSaveRestore clipState(aBuilder);
2991 220 :
2992 : // If there is a current clip, then depending on the container items we
2993 : // create, different things can happen to it. Some container items simply
2994 : // propagate the clip to their children and aren't clipped themselves.
2995 : // But other container items, especially those that establish a different
2996 : // geometry for their contents (e.g. transforms), capture the clip on
2997 : // themselves and unset the clip for their contents. If we create more than
2998 : // one of those container items, the clip will be captured on the outermost
2999 : // one and the inner container items will be unclipped.
3000 : ContainerItemType clipCapturedBy = ContainerItemType::eNone;
3001 110 : if (useFixedPosition) {
3002 110 : clipCapturedBy = ContainerItemType::eFixedPosition;
3003 : } else if (isTransformed) {
3004 110 : const DisplayItemClipChain* currentClip =
3005 : aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder);
3006 22 : if ((hasPerspective || extend3DContext) &&
3007 0 : (currentClip && currentClip->HasRoundedCorners())) {
3008 0 : // If we're creating an nsDisplayTransform item that is going to combine
3009 : // its transform with its children (preserve-3d or perspective), then we
3010 : // can't have an intermediate surface. Mask layers force an intermediate
3011 : // surface, so if we're going to need both then create a separate
3012 : // wrapping layer for the mask.
3013 : clipCapturedBy = ContainerItemType::eOwnLayerForTransformWithRoundedClip;
3014 : } else if (hasPerspective) {
3015 11 : clipCapturedBy = ContainerItemType::ePerspective;
3016 : } else {
3017 : clipCapturedBy = ContainerItemType::eTransform;
3018 11 : }
3019 : } else if (usingFilter) {
3020 0 : clipCapturedBy = ContainerItemType::eFilter;
3021 0 : }
3022 :
3023 : if (clipCapturedBy != ContainerItemType::eNone) {
3024 0 : clipState.Clear();
3025 0 : }
3026 :
3027 : Maybe<nsRect> clipForMask;
3028 220 : if (usingMask) {
3029 110 : clipForMask = ComputeClipForMaskItem(aBuilder, this, !useOpacity);
3030 0 : }
3031 :
3032 : nsDisplayListCollection set(aBuilder);
3033 0 : {
3034 : DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
3035 220 : nsDisplayListBuilder::AutoInTransformSetter
3036 : inTransformSetter(aBuilder, inTransform);
3037 330 : nsDisplayListBuilder::AutoFilterASRSetter
3038 : filterASRSetter(aBuilder, usingFilter);
3039 0 :
3040 : CheckForApzAwareEventHandlers(aBuilder, this);
3041 110 :
3042 : Maybe<nsRect> contentClip =
3043 : GetClipPropClipRect(disp, effects, GetSize());
3044 220 :
3045 : if (usingMask) {
3046 0 : contentClip = IntersectMaybeRects(contentClip, clipForMask);
3047 0 : }
3048 :
3049 : if (contentClip) {
3050 110 : aBuilder->IntersectDirtyRect(*contentClip);
3051 0 : aBuilder->IntersectVisibleRect(*contentClip);
3052 0 : nestedClipState.ClipContentDescendants(*contentClip +
3053 0 : aBuilder->ToReferenceFrame(this));
3054 0 : }
3055 :
3056 : // extend3DContext also guarantees that applyAbsPosClipping and usingSVGEffects are false
3057 : // We only modify the preserve-3d rect if we are the top of a preserve-3d heirarchy
3058 : if (extend3DContext) {
3059 0 : // Mark these first so MarkAbsoluteFramesForDisplayList knows if we are
3060 : // going to be forced to descend into frames.
3061 : aBuilder->MarkPreserve3DFramesForDisplayList(this);
3062 0 : }
3063 :
3064 : aBuilder->AdjustWindowDraggingRegion(this);
3065 0 :
3066 : aBuilder->BuildCompositorHitTestInfoIfNeeded(this, set.BorderBackground(),
3067 110 : true);
3068 0 :
3069 : MarkAbsoluteFramesForDisplayList(aBuilder);
3070 0 : aBuilder->Check();
3071 0 : BuildDisplayList(aBuilder, set);
3072 0 : aBuilder->Check();
3073 220 :
3074 : // Blend modes are a real pain for retained display lists. We build a blend
3075 : // container item if the built list contains any blend mode items within
3076 : // the current stacking context. This can change without an invalidation
3077 : // to the stacking context frame, or the blend mode frame (e.g. by moving
3078 : // an intermediate frame).
3079 : // When we gain/remove a blend container item, we need to mark this frame
3080 : // as invalid and have the full display list for merging to track
3081 : // the change correctly.
3082 : // It seems really hard to track this in advance, as the bookkeeping
3083 : // required to note which stacking contexts have blend descendants
3084 : // is complex and likely to be buggy.
3085 : // Instead we're doing the sad thing, detecting it afterwards, and just
3086 : // repeating display list building if it changed.
3087 : // We have to repeat building for the entire display list (or at least
3088 : // the outer stacking context), since we need to mark this frame as invalid
3089 : // to remove any existing content that isn't wrapped in the blend container,
3090 : // and then we need to build content infront/behind the blend container
3091 : // to get correct positioning during merging.
3092 : if (aBuilder->ContainsBlendMode() &&
3093 0 : aBuilder->IsRetainingDisplayList()) {
3094 0 : if (!aBuilder->GetDirtyRect().Contains(aBuilder->GetVisibleRect())) {
3095 0 : aBuilder->SetPartialBuildFailed(true);
3096 0 : } else {
3097 : aBuilder->SetDisablePartialUpdates(true);
3098 0 : }
3099 : }
3100 : }
3101 :
3102 : if (aBuilder->IsBackgroundOnly()) {
3103 110 : set.BlockBorderBackgrounds()->DeleteAll(aBuilder);
3104 0 : set.Floats()->DeleteAll(aBuilder);
3105 0 : set.Content()->DeleteAll(aBuilder);
3106 0 : set.PositionedDescendants()->DeleteAll(aBuilder);
3107 0 : set.Outlines()->DeleteAll(aBuilder);
3108 0 : }
3109 :
3110 : if (hasOverrideDirtyRect && gfxPrefs::LayoutDisplayListShowArea()) {
3111 110 : nsDisplaySolidColor* color =
3112 : MakeDisplayItem<nsDisplaySolidColor>(aBuilder, this,
3113 0 : dirtyRect + aBuilder->GetCurrentFrameOffsetToReferenceFrame(),
3114 0 : NS_RGBA(255, 0, 0, 64), false);
3115 0 : color->SetOverrideZIndex(INT32_MAX);
3116 0 : set.PositionedDescendants()->AppendToTop(color);
3117 0 : }
3118 :
3119 : // Sort PositionedDescendants() in CSS 'z-order' order. The list is already
3120 : // in content document order and SortByZOrder is a stable sort which
3121 : // guarantees that boxes produced by the same element are placed together
3122 : // in the sort. Consider a position:relative inline element that breaks
3123 : // across lines and has absolutely positioned children; all the abs-pos
3124 : // children should be z-ordered after all the boxes for the position:relative
3125 : // element itself.
3126 : set.PositionedDescendants()->SortByZOrder();
3127 0 :
3128 : nsDisplayList resultList;
3129 220 : // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html
3130 : // 1,2: backgrounds and borders
3131 : resultList.AppendToTop(set.BorderBackground());
3132 110 : // 3: negative z-index children.
3133 : for (;;) {
3134 : nsDisplayItem* item = set.PositionedDescendants()->GetBottom();
3135 1 : if (item && item->ZIndex() < 0) {
3136 110 : set.PositionedDescendants()->RemoveBottom();
3137 0 : resultList.AppendToTop(item);
3138 0 : continue;
3139 : }
3140 : break;
3141 : }
3142 0 : // 4: block backgrounds
3143 : resultList.AppendToTop(set.BlockBorderBackgrounds());
3144 0 : // 5: floats
3145 : resultList.AppendToTop(set.Floats());
3146 110 : // 7: general content
3147 : resultList.AppendToTop(set.Content());
3148 0 : // 7.5: outlines, in content tree order. We need to sort by content order
3149 : // because an element with outline that breaks and has children with outline
3150 : // might have placed child outline items between its own outline items.
3151 : // The element's outline items need to all come before any child outline
3152 : // items.
3153 : nsIContent* content = GetContent();
3154 1 : if (!content) {
3155 110 : content = PresContext()->Document()->GetRootElement();
3156 19 : }
3157 : if (content) {
3158 110 : set.Outlines()->SortByContentOrder(content);
3159 110 : }
3160 : #ifdef DEBUG
3161 : DisplayDebugBorders(aBuilder, this, set);
3162 110 : #endif
3163 : resultList.AppendToTop(set.Outlines());
3164 0 : // 8, 9: non-negative z-index children
3165 : resultList.AppendToTop(set.PositionedDescendants());
3166 0 :
3167 : // Get the ASR to use for the container items that we create here.
3168 : const ActiveScrolledRoot* containerItemASR = contASRTracker.GetContainerASR();
3169 0 :
3170 : if (aCreatedContainerItem) {
3171 110 : *aCreatedContainerItem = false;
3172 0 : }
3173 :
3174 : /* If adding both a nsDisplayBlendContainer and a nsDisplayBlendMode to the
3175 : * same list, the nsDisplayBlendContainer should be added first. This only
3176 : * happens when the element creating this stacking context has mix-blend-mode
3177 : * and also contains a child which has mix-blend-mode.
3178 : * The nsDisplayBlendContainer must be added to the list first, so it does not
3179 : * isolate the containing element blending as well.
3180 : */
3181 : if (aBuilder->ContainsBlendMode()) {
3182 110 : DisplayListClipState::AutoSaveRestore blendContainerClipState(aBuilder);
3183 0 : resultList.AppendToTop(
3184 0 : nsDisplayBlendContainer::CreateForMixBlendMode(aBuilder, this, &resultList,
3185 0 : containerItemASR));
3186 0 : if (aCreatedContainerItem) {
3187 0 : *aCreatedContainerItem = true;
3188 0 : }
3189 : }
3190 :
3191 : /* If there are any SVG effects, wrap the list up in an SVG effects item
3192 : * (which also handles CSS group opacity). Note that we create an SVG effects
3193 : * item even if resultList is empty, since a filter can produce graphical
3194 : * output even if the element being filtered wouldn't otherwise do so.
3195 : */
3196 : if (usingSVGEffects) {
3197 110 : MOZ_ASSERT(usingFilter ||usingMask,
3198 0 : "Beside filter & mask/clip-path, what else effect do we have?");
3199 :
3200 : if (clipCapturedBy == ContainerItemType::eFilter) {
3201 0 : clipState.Restore();
3202 0 : }
3203 : // Revert to the post-filter dirty rect.
3204 : aBuilder->SetVisibleRect(visibleRectOutsideSVGEffects);
3205 0 :
3206 : // Skip all filter effects while generating glyph mask.
3207 : if (usingFilter && !aBuilder->IsForGenerateGlyphMask()) {
3208 0 : // If we are going to create a mask display item, handle opacity effect
3209 : // in that mask display item; Otherwise, take care of opacity in this
3210 : // filter display item.
3211 : bool handleOpacity = !usingMask && !useOpacity;
3212 0 :
3213 : /* List now emptied, so add the new list to the top. */
3214 : resultList.AppendToTop(
3215 : MakeDisplayItem<nsDisplayFilter>(aBuilder, this, &resultList,
3216 0 : handleOpacity));
3217 0 : }
3218 :
3219 : if (usingMask) {
3220 0 : DisplayListClipState::AutoSaveRestore maskClipState(aBuilder);
3221 0 : // The mask should move with aBuilder->CurrentActiveScrolledRoot(), so
3222 : // that's the ASR we prefer to use for the mask item. However, we can
3223 : // only do this if the mask if clipped with respect to that ASR, because
3224 : // an item always needs to have finite bounds with respect to its ASR.
3225 : // If we weren't able to compute a clip for the mask, we fall back to
3226 : // using containerItemASR, which is the lowest common ancestor clip of
3227 : // the mask's contents. That's not entirely crrect, but it satisfies
3228 : // the base requirement of the ASR system (that items have finite bounds
3229 : // wrt. their ASR).
3230 : const ActiveScrolledRoot* maskASR = clipForMask.isSome()
3231 0 : ? aBuilder->CurrentActiveScrolledRoot()
3232 0 : : containerItemASR;
3233 0 : /* List now emptied, so add the new list to the top. */
3234 : resultList.AppendToTop(
3235 0 : MakeDisplayItem<nsDisplayMask>(aBuilder, this, &resultList, !useOpacity,
3236 0 : maskASR));
3237 0 : }
3238 :
3239 : // Also add the hoisted scroll info items. We need those for APZ scrolling
3240 : // because nsDisplayMask items can't build active layers.
3241 : aBuilder->ExitSVGEffectsContents();
3242 0 : resultList.AppendToTop(&hoistedScrollInfoItemsStorage);
3243 0 : if (aCreatedContainerItem) {
3244 0 : *aCreatedContainerItem = false;
3245 0 : }
3246 : }
3247 :
3248 : /* If the list is non-empty and there is CSS group opacity without SVG
3249 : * effects, wrap it up in an opacity item.
3250 : */
3251 : if (useOpacity) {
3252 110 : // Don't clip nsDisplayOpacity items. We clip their descendants instead.
3253 : // The clip we would set on an element with opacity would clip
3254 : // all descendant content, but some should not be clipped.
3255 : DisplayListClipState::AutoSaveRestore opacityClipState(aBuilder);
3256 64 : resultList.AppendToTop(
3257 0 : MakeDisplayItem<nsDisplayOpacity>(aBuilder, this, &resultList,
3258 0 : containerItemASR,
3259 : opacityItemForEventsAndPluginsOnly));
3260 32 : if (aCreatedContainerItem) {
3261 32 : *aCreatedContainerItem = true;
3262 32 : }
3263 : }
3264 :
3265 : /* If we're going to apply a transformation and don't have preserve-3d set, wrap
3266 : * everything in an nsDisplayTransform. If there's nothing in the list, don't add
3267 : * anything.
3268 : *
3269 : * For the preserve-3d case we want to individually wrap every child in the list with
3270 : * a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform,
3271 : * we can skip this step, as the computed transform will already include our own.
3272 : *
3273 : * We also traverse into sublists created by nsDisplayWrapList, so that we find all the
3274 : * correct children.
3275 : */
3276 : if (isTransformed && extend3DContext) {
3277 110 : // Install dummy nsDisplayTransform as a leaf containing
3278 : // descendants not participating this 3D rendering context.
3279 : nsDisplayList nonparticipants;
3280 0 : nsDisplayList participants;
3281 0 : int index = 1;
3282 0 :
3283 : while (nsDisplayItem* item = resultList.RemoveBottom()) {
3284 0 : if (ItemParticipatesIn3DContext(this, item) && !item->GetClip().HasClip()) {
3285 0 : // The frame of this item participates the same 3D context.
3286 : WrapSeparatorTransform(aBuilder, this, &nonparticipants, &participants, index++);
3287 0 : participants.AppendToTop(item);
3288 0 : } else {
3289 : // The frame of the item doesn't participate the current
3290 : // context, or has no transform.
3291 : //
3292 : // For items participating but not transformed, they are add
3293 : // to nonparticipants to get a separator layer for handling
3294 : // clips, if there is, on an intermediate surface.
3295 : // \see ContainerLayer::DefaultComputeEffectiveTransforms().
3296 : nonparticipants.AppendToTop(item);
3297 0 : }
3298 : }
3299 : WrapSeparatorTransform(aBuilder, this, &nonparticipants, &participants, index++);
3300 0 : resultList.AppendToTop(&participants);
3301 0 : }
3302 :
3303 : if (isTransformed) {
3304 110 : if (clipCapturedBy == ContainerItemType::eTransform) {
3305 11 : // Restore clip state now so nsDisplayTransform is clipped properly.
3306 : clipState.Restore();
3307 11 : }
3308 : // Revert to the dirtyrect coming in from the parent, without our transform
3309 : // taken into account.
3310 : aBuilder->SetVisibleRect(visibleRectOutsideTransform);
3311 22 : // Revert to the outer reference frame and offset because all display
3312 : // items we create from now on are outside the transform.
3313 : nsPoint toOuterReferenceFrame;
3314 0 : const nsIFrame* outerReferenceFrame = this;
3315 11 : if (this != aBuilder->RootReferenceFrame()) {
3316 11 : outerReferenceFrame =
3317 : aBuilder->FindReferenceFrameFor(GetParent(), &toOuterReferenceFrame);
3318 0 : }
3319 : buildingDisplayList.SetReferenceFrameAndCurrentOffset(outerReferenceFrame,
3320 : GetOffsetToCrossDoc(outerReferenceFrame));
3321 0 :
3322 : nsDisplayTransform *transformItem =
3323 : MakeDisplayItem<nsDisplayTransform>(aBuilder, this,
3324 0 : &resultList, visibleRect, 0,
3325 0 : allowAsyncAnimation);
3326 11 : resultList.AppendToTop(transformItem);
3327 11 :
3328 : if (hasPerspective) {
3329 11 : if (clipCapturedBy == ContainerItemType::ePerspective) {
3330 0 : clipState.Restore();
3331 0 : }
3332 : resultList.AppendToTop(
3333 0 : MakeDisplayItem<nsDisplayPerspective>(
3334 0 : aBuilder, this, &resultList));
3335 0 : }
3336 :
3337 : if (aCreatedContainerItem) {
3338 0 : *aCreatedContainerItem = true;
3339 11 : }
3340 : }
3341 :
3342 : if (clipCapturedBy == ContainerItemType::eOwnLayerForTransformWithRoundedClip) {
3343 110 : clipState.Restore();
3344 0 : resultList.AppendToTop(
3345 : MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, this, &resultList,
3346 0 : aBuilder->CurrentActiveScrolledRoot(),
3347 0 : nsDisplayOwnLayerFlags::eNone,
3348 : ScrollbarData{}, /* aForceActive = */ false));
3349 0 : if (aCreatedContainerItem) {
3350 0 : *aCreatedContainerItem = true;
3351 0 : }
3352 : }
3353 :
3354 : /* If we have sticky positioning, wrap it in a sticky position item.
3355 : */
3356 : if (useFixedPosition) {
3357 110 : if (clipCapturedBy == ContainerItemType::eFixedPosition) {
3358 0 : clipState.Restore();
3359 0 : }
3360 : // The ASR for the fixed item should be the ASR of our containing block,
3361 : // which has been set as the builder's current ASR, unless this frame is
3362 : // invisible and we hadn't saved display item data for it. In that case,
3363 : // we need to take the containerItemASR since we might have fixed children.
3364 : // For WebRender, we want to the know what |containerItemASR| is for the
3365 : // case where the fixed-pos item is not a "real" fixed-pos item (e.g. it's
3366 : // nested inside a scrolling transform), so we stash that on the display
3367 : // item as well.
3368 : const ActiveScrolledRoot* fixedASR =
3369 : ActiveScrolledRoot::PickAncestor(containerItemASR, aBuilder->CurrentActiveScrolledRoot());
3370 0 : resultList.AppendToTop(
3371 0 : MakeDisplayItem<nsDisplayFixedPosition>(aBuilder, this, &resultList,
3372 0 : fixedASR, containerItemASR));
3373 0 : if (aCreatedContainerItem) {
3374 0 : *aCreatedContainerItem = true;
3375 0 : }
3376 : } else if (useStickyPosition) {
3377 110 : // For position:sticky, the clip needs to be applied both to the sticky
3378 : // container item and to the contents. The container item needs the clip
3379 : // because a scrolled clip needs to move independently from the sticky
3380 : // contents, and the contents need the clip so that they have finite
3381 : // clipped bounds with respect to the container item's ASR. The latter is
3382 : // a little tricky in the case where the sticky item has both fixed and
3383 : // non-fixed descendants, because that means that the sticky container
3384 : // item's ASR is the ASR of the fixed descendant.
3385 : // For WebRender display list building, though, we still want to know the
3386 : // the ASR that the sticky container item would normally have, so we stash
3387 : // that on the display item as the "container ASR" (i.e. the normal ASR of
3388 : // the container item, excluding the special behaviour induced by fixed
3389 : // descendants).
3390 : const ActiveScrolledRoot* stickyASR =
3391 : ActiveScrolledRoot::PickAncestor(containerItemASR, aBuilder->CurrentActiveScrolledRoot());
3392 0 : resultList.AppendToTop(
3393 : MakeDisplayItem<nsDisplayStickyPosition>(aBuilder, this, &resultList,
3394 0 : stickyASR, aBuilder->CurrentActiveScrolledRoot()));
3395 0 : if (aCreatedContainerItem) {
3396 0 : *aCreatedContainerItem = true;
3397 0 : }
3398 : }
3399 :
3400 : /* If there's blending, wrap up the list in a blend-mode item. Note
3401 : * that opacity can be applied before blending as the blend color is
3402 : * not affected by foreground opacity (only background alpha).
3403 : */
3404 :
3405 : if (useBlendMode) {
3406 0 : DisplayListClipState::AutoSaveRestore blendModeClipState(aBuilder);
3407 0 : resultList.AppendToTop(
3408 0 : MakeDisplayItem<nsDisplayBlendMode>(aBuilder, this, &resultList,
3409 0 : effects->mMixBlendMode,
3410 : containerItemASR));
3411 0 : if (aCreatedContainerItem) {
3412 0 : *aCreatedContainerItem = true;
3413 0 : }
3414 : }
3415 :
3416 : CreateOwnLayerIfNeeded(aBuilder, &resultList, aCreatedContainerItem);
3417 110 :
3418 : aList->AppendToTop(&resultList);
3419 110 : }
3420 :
3421 : static nsDisplayItem*
3422 : WrapInWrapList(nsDisplayListBuilder* aBuilder,
3423 125 : nsIFrame* aFrame, nsDisplayList* aList,
3424 : const ActiveScrolledRoot* aContainerASR,
3425 : bool aCanSkipWrapList = false)
3426 : {
3427 : nsDisplayItem* item = aList->GetBottom();
3428 0 : if (!item) {
3429 0 : return nullptr;
3430 : }
3431 :
3432 : if (aCanSkipWrapList) {
3433 125 : MOZ_ASSERT(!item->GetAbove());
3434 43 : aList->RemoveBottom();
3435 43 : return item;
3436 43 : }
3437 :
3438 : // Clear clip rect for the construction of the items below. Since we're
3439 : // clipping all their contents, they themselves don't need to be clipped.
3440 : return MakeDisplayItem<nsDisplayWrapList>(aBuilder, aFrame, aList, aContainerASR, true);
3441 0 : }
3442 :
3443 : /**
3444 : * Check if a frame should be visited for building display list.
3445 : */
3446 : static bool
3447 : DescendIntoChild(nsDisplayListBuilder* aBuilder, nsIFrame *aChild,
3448 871 : const nsRect& aVisible, const nsRect& aDirty)
3449 : {
3450 : nsIFrame* child = aChild;
3451 0 : const nsRect& dirty = aDirty;
3452 871 :
3453 : if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
3454 1742 : // No need to descend into child to catch placeholders for visible
3455 : // positioned stuff. So see if we can short-circuit frame traversal here.
3456 :
3457 : // We can stop if child's frame subtree's intersection with the
3458 : // dirty area is empty.
3459 : // If the child is a scrollframe that we want to ignore, then we need
3460 : // to descend into it because its scrolled child may intersect the dirty
3461 : // area even if the scrollframe itself doesn't.
3462 : // There are cases where the "ignore scroll frame" on the builder is not set
3463 : // correctly, and so we additionally want to catch cases where the child is
3464 : // a root scrollframe and we are ignoring scrolling on the viewport.
3465 : nsIPresShell* shell = child->PresShell();
3466 0 : bool keepDescending = child == aBuilder->GetIgnoreScrollFrame() ||
3467 0 : (shell->IgnoringViewportScrolling() && child == shell->GetRootScrollFrame());
3468 0 : if (!keepDescending) {
3469 691 : nsRect childDirty;
3470 1174 : if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect()) &&
3471 866 : (!child->ForceDescendIntoIfVisible())) {
3472 186 : return false;
3473 0 : }
3474 : if (!childDirty.IntersectRect(aVisible, child->GetVisualOverflowRect())) {
3475 494 : return false;
3476 : }
3477 : // Usually we could set dirty to childDirty now but there's no
3478 : // benefit, and it can be confusing. It can especially confuse
3479 : // situations where we're going to ignore a scrollframe's clipping;
3480 : // we wouldn't want to clip the dirty area to the scrollframe's
3481 : // bounds in that case.
3482 : }
3483 : }
3484 : return true;
3485 : }
3486 :
3487 : void
3488 : nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
3489 1039 : nsIFrame* aChild,
3490 : const nsDisplayListSet& aLists,
3491 : uint32_t aFlags) {
3492 : AutoCheckBuilder check(aBuilder);
3493 1180 : // If painting is restricted to just the background of the top level frame,
3494 : // then we have nothing to do here.
3495 : if (aBuilder->IsBackgroundOnly())
3496 1039 : return;
3497 898 :
3498 : if (aBuilder->IsForGenerateGlyphMask() ||
3499 0 : aBuilder->IsForPaintingSelectionBG()) {
3500 0 : if (!aChild->IsTextFrame() && aChild->IsLeaf()) {
3501 0 : return;
3502 : }
3503 : }
3504 :
3505 : nsIFrame* child = aChild;
3506 1039 : if (child->HasAnyStateBits(
3507 0 : NS_FRAME_TOO_DEEP_IN_FRAME_TREE | NS_FRAME_IS_NONDISPLAY))
3508 : return;
3509 :
3510 : aBuilder->ClearWillChangeBudget(child);
3511 1039 :
3512 : const bool shortcutPossible = aBuilder->IsPaintingToWindow() &&
3513 2021 : aBuilder->BuildCompositorHitTestInfo();
3514 2021 :
3515 : const bool doingShortcut = shortcutPossible &&
3516 982 : (child->GetStateBits() & NS_FRAME_SIMPLE_DISPLAYLIST) &&
3517 2383 : // Animations may change the value of |HasOpacity()|.
3518 : !(child->GetContent() &&
3519 1086 : child->GetContent()->MayHaveAnimations());
3520 2125 :
3521 : // dirty rect in child-relative coordinates
3522 : NS_ASSERTION(aBuilder->GetCurrentFrame() == this, "Wrong coord space!");
3523 1039 : const nsPoint offset = child->GetOffsetTo(this);
3524 2078 : nsRect visible = aBuilder->GetVisibleRect() - offset;
3525 0 : nsRect dirty = aBuilder->GetDirtyRect() - offset;
3526 1180 :
3527 : if (doingShortcut) {
3528 0 : // This is the shortcut for frames been handled along the common
3529 : // path, the most common one of THE COMMON CASE mentioned later.
3530 : MOZ_ASSERT(child->Type() != LayoutFrameType::Placeholder);
3531 0 : MOZ_ASSERT(!aBuilder->GetSelectedFramesOnly() &&
3532 0 : !aBuilder->GetIncludeAllOutOfFlows(),
3533 : "It should be held for painting to window");
3534 :
3535 : if (!DescendIntoChild(aBuilder, child, visible, dirty)) {
3536 362 : return;
3537 : }
3538 :
3539 : nsDisplayListBuilder::AutoBuildingDisplayList
3540 : buildingForChild(aBuilder, child, visible, dirty, false);
3541 724 :
3542 : CheckForApzAwareEventHandlers(aBuilder, child);
3543 0 :
3544 : aBuilder->BuildCompositorHitTestInfoIfNeeded(child,
3545 0 : aLists.BorderBackground(),
3546 : false);
3547 0 :
3548 : child->MarkAbsoluteFramesForDisplayList(aBuilder);
3549 0 : aBuilder->AdjustWindowDraggingRegion(child);
3550 0 : aBuilder->Check();
3551 362 : child->BuildDisplayList(aBuilder, aLists);
3552 0 : aBuilder->Check();
3553 0 : aBuilder->DisplayCaret(child, aLists.Content());
3554 362 : #ifdef DEBUG
3555 : DisplayDebugBorders(aBuilder, child, aLists);
3556 0 : #endif
3557 : return;
3558 : }
3559 :
3560 : const bool isSVG = child->GetStateBits() & NS_FRAME_SVG_LAYOUT;
3561 0 :
3562 : // It is raised if the control flow strays off the common path.
3563 : // The common path is the most common one of THE COMMON CASE
3564 : // mentioned later.
3565 : bool awayFromCommonPath = false;
3566 677 :
3567 : // true if this is a real or pseudo stacking context
3568 : bool pseudoStackingContext =
3569 : (aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
3570 677 :
3571 : if (!pseudoStackingContext &&
3572 2031 : !isSVG &&
3573 1330 : (aFlags & DISPLAY_CHILD_INLINE) &&
3574 0 : !child->IsFrameOfType(eLineParticipant)) {
3575 5 : // child is a non-inline frame in an inline context, i.e.,
3576 : // it acts like inline-block or inline-table. Therefore it is a
3577 : // pseudo-stacking-context.
3578 : pseudoStackingContext = true;
3579 0 : }
3580 :
3581 : nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr;
3582 0 : bool isPlaceholder = false;
3583 0 : if (child->IsPlaceholderFrame()) {
3584 1 : isPlaceholder = true;
3585 186 : nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child);
3586 186 : child = placeholder->GetOutOfFlowFrame();
3587 0 : aBuilder->ClearWillChangeBudget(child);
3588 0 : NS_ASSERTION(child, "No out of flow frame?");
3589 0 : // If 'child' is a pushed float then it's owned by a block that's not an
3590 : // ancestor of the placeholder, and it will be painted by that block and
3591 : // should not be painted through the placeholder.
3592 : if (!child || nsLayoutUtils::IsPopup(child) ||
3593 204 : (child->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT))
3594 0 : return;
3595 : MOZ_ASSERT(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW);
3596 36 : // If the out-of-flow frame is in the top layer, the viewport frame
3597 : // will paint it. Skip it here. Note that, only out-of-flow frames
3598 : // with this property should be skipped, because non-HTML elements
3599 : // may stop their children from being out-of-flow. Those frames
3600 : // should still be handled in the normal in-flow path.
3601 : if (placeholder->GetStateBits() & PLACEHOLDER_FOR_TOPLAYER) {
3602 36 : return;
3603 : }
3604 : // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
3605 : if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
3606 36 : return;
3607 : savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(child);
3608 0 : if (savedOutOfFlowData) {
3609 18 : visible = savedOutOfFlowData->GetVisibleRectForFrame(aBuilder, child, &dirty);
3610 0 : } else {
3611 : // The out-of-flow frame did not intersect the dirty area. We may still
3612 : // need to traverse into it, since it may contain placeholders we need
3613 : // to enter to reach other out-of-flow frames that are visible.
3614 : visible.SetEmpty();
3615 0 : dirty.SetEmpty();
3616 : }
3617 :
3618 : pseudoStackingContext = true;
3619 : }
3620 :
3621 : NS_ASSERTION(!child->IsPlaceholderFrame(),
3622 0 : "Should have dealt with placeholders already");
3623 : if (aBuilder->GetSelectedFramesOnly() &&
3624 0 : child->IsLeaf() &&
3625 0 : !aChild->IsSelected()) {
3626 0 : return;
3627 : }
3628 :
3629 : if (aBuilder->GetIncludeAllOutOfFlows() && isPlaceholder) {
3630 509 : visible = child->GetVisualOverflowRect();
3631 0 : dirty = child->GetVisualOverflowRect();
3632 0 : } else if (!DescendIntoChild(aBuilder, child, visible, dirty)) {
3633 509 : return;
3634 : }
3635 :
3636 : // XXX need to have inline-block and inline-table set pseudoStackingContext
3637 :
3638 : const nsStyleDisplay* ourDisp = StyleDisplay();
3639 323 : // REVIEW: Taken from nsBoxFrame::Paint
3640 : // Don't paint our children if the theme object is a leaf.
3641 : if (IsThemed(ourDisp) &&
3642 355 : !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance))
3643 32 : return;
3644 :
3645 : // Since we're now sure that we're adding this frame to the display list
3646 : // (which means we're painting it, modulo occlusion), mark it as visible
3647 : // within the displayport.
3648 : if (aBuilder->IsPaintingToWindow() && child->TrackingVisibility()) {
3649 589 : child->PresShell()->EnsureFrameInApproximatelyVisibleList(child);
3650 0 : awayFromCommonPath = true;
3651 0 : }
3652 :
3653 : child->SetBuiltDisplayList(true);
3654 646 :
3655 : // Child is composited if it's transformed, partially transparent, or has
3656 : // SVG effects or a blend mode..
3657 : EffectSet* effectSet = EffectSet::GetEffectSet(child);
3658 323 : const nsStyleDisplay* disp = child->StyleDisplay();
3659 323 : const nsStyleEffects* effects = child->StyleEffects();
3660 0 : const nsStylePosition* pos = child->StylePosition();
3661 323 :
3662 : const bool isVisuallyAtomic =
3663 : child->IsVisuallyAtomic(effectSet, disp, effects);
3664 1 :
3665 : const bool isPositioned =
3666 : disp->IsAbsPosContainingBlock(child);
3667 323 :
3668 : const bool isStackingContext =
3669 : child->IsStackingContext(disp, pos, isPositioned, isVisuallyAtomic) ||
3670 1 : (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
3671 0 :
3672 : if (pseudoStackingContext || isStackingContext || isPositioned ||
3673 852 : (!isSVG && disp->IsFloating(child)) ||
3674 492 : (isSVG && (effects->mClipFlags & NS_STYLE_CLIP_RECT) &&
3675 13 : IsSVGContentWithCSSClip(child))) {
3676 0 : pseudoStackingContext = true;
3677 0 : awayFromCommonPath = true;
3678 141 : }
3679 :
3680 : NS_ASSERTION(!isStackingContext || pseudoStackingContext,
3681 0 : "Stacking contexts must also be pseudo-stacking-contexts");
3682 :
3683 : nsDisplayListBuilder::AutoBuildingDisplayList
3684 : buildingForChild(aBuilder, child, visible, dirty, pseudoStackingContext);
3685 464 : DisplayListClipState::AutoClipMultiple clipState(aBuilder);
3686 464 : nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
3687 0 : CheckForApzAwareEventHandlers(aBuilder, child);
3688 0 :
3689 : if (savedOutOfFlowData) {
3690 323 : aBuilder->SetBuildingInvisibleItems(false);
3691 18 :
3692 : clipState.SetClipChainForContainingBlockDescendants(
3693 18 : savedOutOfFlowData->mContainingBlockClipChain);
3694 36 : asrSetter.SetCurrentActiveScrolledRoot(
3695 18 : savedOutOfFlowData->mContainingBlockActiveScrolledRoot);
3696 0 : MOZ_ASSERT(awayFromCommonPath, "It is impossible when savedOutOfFlowData is true");
3697 0 : } else if (GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO &&
3698 0 : isPlaceholder) {
3699 : NS_ASSERTION(visible.IsEmpty(), "should have empty visible rect");
3700 0 : // Every item we build from now until we descent into an out of flow that
3701 : // does have saved out of flow data should be invisible. This state gets
3702 : // restored when AutoBuildingDisplayList gets out of scope.
3703 : aBuilder->SetBuildingInvisibleItems(true);
3704 0 :
3705 : // If we have nested out-of-flow frames and the outer one isn't visible
3706 : // then we won't have stored clip data for it. We can just clear the clip
3707 : // instead since we know we won't render anything, and the inner out-of-flow
3708 : // frame will setup the correct clip for itself.
3709 : clipState.SetClipChainForContainingBlockDescendants(nullptr);
3710 0 : }
3711 :
3712 : // Setup clipping for the parent's overflow:-moz-hidden-unscrollable,
3713 : // or overflow:hidden on elements that don't support scrolling (and therefore
3714 : // don't create nsHTML/XULScrollFrame). This clipping needs to not clip
3715 : // anything directly rendered by the parent, only the rendering of its
3716 : // children.
3717 : // Don't use overflowClip to restrict the dirty rect, since some of the
3718 : // descendants may not be clipped by it. Even if we end up with unnecessary
3719 : // display items, they'll be pruned during ComputeVisibility.
3720 : nsIFrame* parent = child->GetParent();
3721 323 : const nsStyleDisplay* parentDisp =
3722 : parent == this ? ourDisp : parent->StyleDisplay();
3723 0 : if (ApplyOverflowClipping(aBuilder, parent, parentDisp, clipState)) {
3724 0 : awayFromCommonPath = true;
3725 0 : }
3726 :
3727 : nsDisplayList list;
3728 0 : nsDisplayList extraPositionedDescendants;
3729 0 : const ActiveScrolledRoot* wrapListASR;
3730 : bool canSkipWrapList = false;
3731 0 : if (isStackingContext) {
3732 0 : if (effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
3733 0 : aBuilder->SetContainsBlendMode(true);
3734 : }
3735 : // True stacking context.
3736 : // For stacking contexts, BuildDisplayListForStackingContext handles
3737 : // clipping and MarkAbsoluteFramesForDisplayList.
3738 : nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
3739 214 : child->BuildDisplayListForStackingContext(aBuilder, &list, &canSkipWrapList);
3740 107 : wrapListASR = contASRTracker.GetContainerASR();
3741 214 : if (aBuilder->DisplayCaret(child, &list)) {
3742 1 : canSkipWrapList = false;
3743 0 : }
3744 : } else {
3745 : Maybe<nsRect> clipPropClip =
3746 : child->GetClipPropClipRect(disp, effects, child->GetSize());
3747 466 : if (clipPropClip) {
3748 1 : aBuilder->IntersectVisibleRect(*clipPropClip);
3749 0 : aBuilder->IntersectDirtyRect(*clipPropClip);
3750 0 : clipState.ClipContentDescendants(
3751 : *clipPropClip + aBuilder->ToReferenceFrame(child));
3752 0 : awayFromCommonPath = true;
3753 0 : }
3754 :
3755 : child->MarkAbsoluteFramesForDisplayList(aBuilder);
3756 216 :
3757 : const bool differentAGR =
3758 : buildingForChild.IsAnimatedGeometryRoot() || isPositioned;
3759 0 :
3760 : if (!awayFromCommonPath && shortcutPossible &&
3761 0 : !differentAGR && !buildingForChild.MaybeAnimatedGeometryRoot()) {
3762 0 : // The shortcut is available for the child for next time.
3763 : child->AddStateBits(NS_FRAME_SIMPLE_DISPLAYLIST);
3764 54 : }
3765 :
3766 : if (!pseudoStackingContext) {
3767 0 : // THIS IS THE COMMON CASE.
3768 : // Not a pseudo or real stacking context. Do the simple thing and
3769 : // return early.
3770 :
3771 : aBuilder->BuildCompositorHitTestInfoIfNeeded(child,
3772 182 : aLists.BorderBackground(),
3773 : differentAGR);
3774 182 :
3775 : aBuilder->AdjustWindowDraggingRegion(child);
3776 182 : aBuilder->Check();
3777 0 : child->BuildDisplayList(aBuilder, aLists);
3778 0 : aBuilder->Check();
3779 0 : aBuilder->DisplayCaret(child, aLists.Content());
3780 0 : #ifdef DEBUG
3781 : DisplayDebugBorders(aBuilder, child, aLists);
3782 182 : #endif
3783 : return;
3784 182 : }
3785 :
3786 : // A pseudo-stacking context (e.g., a positioned element with z-index auto).
3787 : // We allow positioned descendants of the child to escape to our parent
3788 : // stacking context's positioned descendant list, because they might be
3789 : // z-index:non-auto
3790 : nsDisplayListCollection pseudoStack(aBuilder);
3791 0 :
3792 : aBuilder->BuildCompositorHitTestInfoIfNeeded(child,
3793 34 : pseudoStack.BorderBackground(),
3794 : differentAGR);
3795 34 :
3796 : aBuilder->AdjustWindowDraggingRegion(child);
3797 34 : nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
3798 68 : aBuilder->Check();
3799 1 : child->BuildDisplayList(aBuilder, pseudoStack);
3800 34 : aBuilder->Check();
3801 1 : if (aBuilder->DisplayCaret(child, pseudoStack.Content())) {
3802 1 : canSkipWrapList = false;
3803 0 : }
3804 : wrapListASR = contASRTracker.GetContainerASR();
3805 1 :
3806 : list.AppendToTop(pseudoStack.BorderBackground());
3807 34 : list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
3808 1 : list.AppendToTop(pseudoStack.Floats());
3809 34 : list.AppendToTop(pseudoStack.Content());
3810 1 : list.AppendToTop(pseudoStack.Outlines());
3811 34 : extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants());
3812 34 : #ifdef DEBUG
3813 : DisplayDebugBorders(aBuilder, child, aLists);
3814 1 : #endif
3815 : }
3816 :
3817 : buildingForChild.RestoreBuildingInvisibleItemsValue();
3818 141 :
3819 : if (isPositioned || isVisuallyAtomic ||
3820 171 : (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
3821 0 : // Genuine stacking contexts, and positioned pseudo-stacking-contexts,
3822 : // go in this level.
3823 : if (!list.IsEmpty()) {
3824 0 : nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list, wrapListASR, canSkipWrapList);
3825 125 : if (isSVG) {
3826 0 : aLists.Content()->AppendToTop(item);
3827 11 : } else {
3828 : aLists.PositionedDescendants()->AppendToTop(item);
3829 0 : }
3830 : }
3831 : } else if (!isSVG && disp->IsFloating(child)) {
3832 0 : if (!list.IsEmpty()) {
3833 0 : aLists.Floats()->AppendToTop(WrapInWrapList(aBuilder, child, &list, wrapListASR));
3834 0 : }
3835 : } else {
3836 : aLists.Content()->AppendToTop(&list);
3837 0 : }
3838 : // We delay placing the positioned descendants of positioned frames to here,
3839 : // because in the absence of z-index this is the correct order for them.
3840 : // This doesn't affect correctness because the positioned descendants list
3841 : // is sorted by z-order and content in BuildDisplayListForStackingContext,
3842 : // but it means that sort routine needs to do less work.
3843 : aLists.PositionedDescendants()->AppendToTop(&extraPositionedDescendants);
3844 0 : }
3845 :
3846 : void
3847 : nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder)
3848 688 : {
3849 : if (IsAbsoluteContainer()) {
3850 1376 : aBuilder->MarkFramesForDisplayList(this, GetAbsoluteContainingBlock()->GetChildList());
3851 164 : }
3852 : }
3853 0 :
3854 : nsresult
3855 : nsFrame::GetContentForEvent(WidgetEvent* aEvent,
3856 0 : nsIContent** aContent)
3857 : {
3858 : nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(this);
3859 0 : *aContent = f->GetContent();
3860 0 : NS_IF_ADDREF(*aContent);
3861 0 : return NS_OK;
3862 0 : }
3863 :
3864 : void
3865 : nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent)
3866 0 : {
3867 : nsIContent* target = aContent ? aContent : GetContent();
3868 0 :
3869 : if (target) {
3870 0 : RefPtr<AsyncEventDispatcher> asyncDispatcher =
3871 : new AsyncEventDispatcher(target, aDOMEventName, true, false);
3872 0 : DebugOnly<nsresult> rv = asyncDispatcher->PostDOMEvent();
3873 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncEventDispatcher failed to dispatch");
3874 0 : }
3875 : }
3876 0 :
3877 : nsresult
3878 : nsFrame::HandleEvent(nsPresContext* aPresContext,
3879 0 : WidgetGUIEvent* aEvent,
3880 : nsEventStatus* aEventStatus)
3881 : {
3882 :
3883 : if (aEvent->mMessage == eMouseMove) {
3884 0 : // XXX If the second argument of HandleDrag() is WidgetMouseEvent,
3885 : // the implementation becomes simpler.
3886 : return HandleDrag(aPresContext, aEvent, aEventStatus);
3887 0 : }
3888 :
3889 : if ((aEvent->mClass == eMouseEventClass &&
3890 0 : aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) ||
3891 0 : aEvent->mClass == eTouchEventClass) {
3892 0 : if (aEvent->mMessage == eMouseDown || aEvent->mMessage == eTouchStart) {
3893 0 : HandlePress(aPresContext, aEvent, aEventStatus);
3894 0 : } else if (aEvent->mMessage == eMouseUp || aEvent->mMessage == eTouchEnd) {
3895 0 : HandleRelease(aPresContext, aEvent, aEventStatus);
3896 0 : }
3897 : }
3898 : return NS_OK;
3899 : }
3900 :
3901 : nsresult
3902 : nsFrame::GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
3903 0 : nsIPresShell* aPresShell,
3904 : WidgetMouseEvent* aMouseEvent,
3905 : nsIContent** aParentContent,
3906 : int32_t* aContentOffset,
3907 : TableSelection* aTarget)
3908 : {
3909 : if (!aFrameSelection || !aPresShell || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
3910 0 : return NS_ERROR_NULL_POINTER;
3911 :
3912 : *aParentContent = nullptr;
3913 0 : *aContentOffset = 0;
3914 0 : *aTarget = TableSelection::None;
3915 0 :
3916 : int16_t displaySelection = aPresShell->GetSelectionFlags();
3917 0 :
3918 : bool selectingTableCells = aFrameSelection->GetTableCellSelection();
3919 0 :
3920 : // DISPLAY_ALL means we're in an editor.
3921 : // If already in cell selection mode,
3922 : // continue selecting with mouse drag or end on mouse up,
3923 : // or when using shift key to extend block of cells
3924 : // (Mouse down does normal selection unless Ctrl/Cmd is pressed)
3925 : bool doTableSelection =
3926 : displaySelection == nsISelectionDisplay::DISPLAY_ALL && selectingTableCells &&
3927 0 : (aMouseEvent->mMessage == eMouseMove ||
3928 0 : (aMouseEvent->mMessage == eMouseUp &&
3929 0 : aMouseEvent->button == WidgetMouseEvent::eLeftButton) ||
3930 0 : aMouseEvent->IsShift());
3931 0 :
3932 : if (!doTableSelection)
3933 0 : {
3934 : // In Browser, special 'table selection' key must be pressed for table selection
3935 : // or when just Shift is pressed and we're already in table/cell selection mode
3936 : #ifdef XP_MACOSX
3937 : doTableSelection = aMouseEvent->IsMeta() || (aMouseEvent->IsShift() && selectingTableCells);
3938 : #else
3939 : doTableSelection = aMouseEvent->IsControl() || (aMouseEvent->IsShift() && selectingTableCells);
3940 0 : #endif
3941 : }
3942 : if (!doTableSelection)
3943 0 : return NS_OK;
3944 :
3945 : // Get the cell frame or table frame (or parent) of the current content node
3946 : nsIFrame *frame = this;
3947 0 : bool foundCell = false;
3948 0 : bool foundTable = false;
3949 0 :
3950 : // Get the limiting node to stop parent frame search
3951 : nsIContent* limiter = aFrameSelection->GetLimiter();
3952 0 :
3953 : // If our content node is an ancestor of the limiting node,
3954 : // we should stop the search right now.
3955 : if (limiter && nsContentUtils::ContentIsDescendantOf(limiter, GetContent()))
3956 0 : return NS_OK;
3957 :
3958 : //We don't initiate row/col selection from here now,
3959 : // but we may in future
3960 : //bool selectColumn = false;
3961 : //bool selectRow = false;
3962 :
3963 : while (frame)
3964 0 : {
3965 : // Check for a table cell by querying to a known CellFrame interface
3966 : nsITableCellLayout *cellElement = do_QueryFrame(frame);
3967 0 : if (cellElement)
3968 0 : {
3969 : foundCell = true;
3970 : //TODO: If we want to use proximity to top or left border
3971 : // for row and column selection, this is the place to do it
3972 : break;
3973 : }
3974 : else
3975 : {
3976 : // If not a cell, check for table
3977 : // This will happen when starting frame is the table or child of a table,
3978 : // such as a row (we were inbetween cells or in table border)
3979 : nsTableWrapperFrame *tableFrame = do_QueryFrame(frame);
3980 0 : if (tableFrame)
3981 0 : {
3982 : foundTable = true;
3983 : //TODO: How can we select row when along left table edge
3984 : // or select column when along top edge?
3985 : break;
3986 : } else {
3987 : frame = frame->GetParent();
3988 0 : // Stop if we have hit the selection's limiting content node
3989 : if (frame && frame->GetContent() == limiter)
3990 0 : break;
3991 : }
3992 : }
3993 : }
3994 : // We aren't in a cell or table
3995 : if (!foundCell && !foundTable) return NS_OK;
3996 0 :
3997 : nsIContent* tableOrCellContent = frame->GetContent();
3998 0 : if (!tableOrCellContent) return NS_ERROR_FAILURE;
3999 0 :
4000 : nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent();
4001 0 : if (!parentContent) return NS_ERROR_FAILURE;
4002 0 :
4003 : int32_t offset = parentContent->ComputeIndexOf(tableOrCellContent);
4004 0 : // Not likely?
4005 : if (offset < 0) return NS_ERROR_FAILURE;
4006 0 :
4007 : // Everything is OK -- set the return values
4008 : parentContent.forget(aParentContent);
4009 0 :
4010 : *aContentOffset = offset;
4011 0 :
4012 : #if 0
4013 : if (selectRow)
4014 : *aTarget = TableSelection::Row;
4015 : else if (selectColumn)
4016 : *aTarget = TableSelection::Column;
4017 : else
4018 : #endif
4019 : if (foundCell)
4020 0 : *aTarget = TableSelection::Cell;
4021 0 : else if (foundTable)
4022 0 : *aTarget = TableSelection::Table;
4023 0 :
4024 : return NS_OK;
4025 : }
4026 :
4027 : bool
4028 : nsIFrame::IsSelectable(StyleUserSelect* aSelectStyle) const
4029 0 : {
4030 : // it's ok if aSelectStyle is null
4031 :
4032 : // Like 'visibility', we must check all the parents: if a parent
4033 : // is not selectable, none of its children is selectable.
4034 : //
4035 : // The -moz-all value acts similarly: if a frame has 'user-select:-moz-all',
4036 : // all its children are selectable, even those with 'user-select:none'.
4037 : //
4038 : // As a result, if 'none' and '-moz-all' are not present in the frame hierarchy,
4039 : // aSelectStyle returns the first style that is not AUTO. If these values
4040 : // are present in the frame hierarchy, aSelectStyle returns the style of the
4041 : // topmost parent that has either 'none' or '-moz-all'.
4042 : //
4043 : // The -moz-text value acts as a way to override an ancestor's all/-moz-all value.
4044 : //
4045 : // For instance, if the frame hierarchy is:
4046 : // AUTO -> _MOZ_ALL -> NONE -> TEXT, the returned value is ALL
4047 : // AUTO -> _MOZ_ALL -> NONE -> _MOZ_TEXT, the returned value is TEXT.
4048 : // TEXT -> NONE -> AUTO -> _MOZ_ALL, the returned value is TEXT
4049 : // _MOZ_ALL -> TEXT -> AUTO -> AUTO, the returned value is ALL
4050 : // _MOZ_ALL -> _MOZ_TEXT -> AUTO -> AUTO, the returned value is TEXT.
4051 : // AUTO -> CELL -> TEXT -> AUTO, the returned value is TEXT
4052 : //
4053 : StyleUserSelect selectStyle = StyleUserSelect::Auto;
4054 0 : nsIFrame* frame = const_cast<nsIFrame*>(this);
4055 0 : bool containsEditable = false;
4056 0 :
4057 : while (frame) {
4058 0 : const nsStyleUIReset* userinterface = frame->StyleUIReset();
4059 0 : switch (userinterface->mUserSelect) {
4060 0 : case StyleUserSelect::All:
4061 : case StyleUserSelect::MozAll:
4062 : {
4063 : // override the previous values
4064 : if (selectStyle != StyleUserSelect::MozText) {
4065 0 : selectStyle = userinterface->mUserSelect;
4066 0 : }
4067 : nsIContent* frameContent = frame->GetContent();
4068 0 : containsEditable = frameContent &&
4069 0 : frameContent->EditableDescendantCount() > 0;
4070 0 : break;
4071 : }
4072 : default:
4073 : // otherwise return the first value which is not 'auto'
4074 : if (selectStyle == StyleUserSelect::Auto) {
4075 0 : selectStyle = userinterface->mUserSelect;
4076 0 : }
4077 : break;
4078 : }
4079 : frame = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
4080 0 : }
4081 :
4082 : // convert internal values to standard values
4083 : if (selectStyle == StyleUserSelect::Auto ||
4084 0 : selectStyle == StyleUserSelect::MozText) {
4085 0 : selectStyle = StyleUserSelect::Text;
4086 : } else if (selectStyle == StyleUserSelect::MozAll) {
4087 0 : selectStyle = StyleUserSelect::All;
4088 0 : }
4089 :
4090 : // If user tries to select all of a non-editable content,
4091 : // prevent selection if it contains editable content.
4092 : bool allowSelection = true;
4093 0 : if (selectStyle == StyleUserSelect::All) {
4094 0 : allowSelection = !containsEditable;
4095 0 : }
4096 :
4097 : // return stuff
4098 : if (aSelectStyle) {
4099 0 : *aSelectStyle = selectStyle;
4100 0 : }
4101 :
4102 : return !(mState & NS_FRAME_GENERATED_CONTENT) &&
4103 0 : allowSelection &&
4104 0 : selectStyle != StyleUserSelect::None;
4105 0 : }
4106 :
4107 : /**
4108 : * Handles the Mouse Press Event for the frame
4109 : */
4110 : NS_IMETHODIMP
4111 : nsFrame::HandlePress(nsPresContext* aPresContext,
4112 0 : WidgetGUIEvent* aEvent,
4113 : nsEventStatus* aEventStatus)
4114 : {
4115 : NS_ENSURE_ARG_POINTER(aEventStatus);
4116 0 : if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
4117 0 : return NS_OK;
4118 : }
4119 :
4120 : NS_ENSURE_ARG_POINTER(aEvent);
4121 0 : if (aEvent->mClass == eTouchEventClass) {
4122 0 : return NS_OK;
4123 : }
4124 :
4125 : //We often get out of sync state issues with mousedown events that
4126 : //get interrupted by alerts/dialogs.
4127 : //Check with the ESM to see if we should process this one
4128 : if (!aPresContext->EventStateManager()->EventStatusOK(aEvent))
4129 0 : return NS_OK;
4130 :
4131 : nsIPresShell *shell = aPresContext->GetPresShell();
4132 0 : if (!shell)
4133 0 : return NS_ERROR_FAILURE;
4134 :
4135 : // if we are in Navigator and the click is in a draggable node, we don't want
4136 : // to start selection because we don't want to interfere with a potential
4137 : // drag of said node and steal all its glory.
4138 : int16_t isEditor = shell->GetSelectionFlags();
4139 0 : //weaaak. only the editor can display frame selection not just text and images
4140 : isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
4141 0 :
4142 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
4143 0 :
4144 : if (!mouseEvent->IsAlt()) {
4145 0 : for (nsIContent* content = mContent; content;
4146 0 : content = content->GetParent()) {
4147 0 : if (nsContentUtils::ContentIsDraggable(content) &&
4148 0 : !content->IsEditable()) {
4149 0 : // coordinate stuff is the fix for bug #55921
4150 : if ((mRect - GetPosition()).Contains(
4151 0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this))) {
4152 0 : return NS_OK;
4153 : }
4154 : }
4155 : }
4156 : }
4157 :
4158 : // check whether style allows selection
4159 : // if not, don't tell selection the mouse event even occurred.
4160 : StyleUserSelect selectStyle;
4161 : // check for select: none
4162 : if (!IsSelectable(&selectStyle)) {
4163 0 : return NS_OK;
4164 : }
4165 :
4166 : // When implementing StyleUserSelect::Element, StyleUserSelect::Elements and
4167 : // StyleUserSelect::Toggle, need to change this logic
4168 : bool useFrameSelection = (selectStyle == StyleUserSelect::Text);
4169 0 :
4170 : // If the mouse is dragged outside the nearest enclosing scrollable area
4171 : // while making a selection, the area will be scrolled. To do this, capture
4172 : // the mouse on the nearest scrollable frame. If there isn't a scrollable
4173 : // frame, or something else is already capturing the mouse, there's no
4174 : // reason to capture.
4175 : if (!nsIPresShell::GetCapturingContent()) {
4176 0 : nsIScrollableFrame* scrollFrame =
4177 : nsLayoutUtils::GetNearestScrollableFrame(this,
4178 : nsLayoutUtils::SCROLLABLE_SAME_DOC |
4179 : nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4180 0 : if (scrollFrame) {
4181 0 : nsIFrame* capturingFrame = do_QueryFrame(scrollFrame);
4182 0 : nsIPresShell::SetCapturingContent(capturingFrame->GetContent(),
4183 0 : CAPTURE_IGNOREALLOWED);
4184 0 : }
4185 : }
4186 :
4187 : // XXX This is screwy; it really should use the selection frame, not the
4188 : // event frame
4189 : const nsFrameSelection* frameselection = nullptr;
4190 0 : if (useFrameSelection)
4191 0 : frameselection = GetConstFrameSelection();
4192 0 : else
4193 : frameselection = shell->ConstFrameSelection();
4194 0 :
4195 : if (!frameselection || frameselection->GetDisplaySelection() == nsISelectionController::SELECTION_OFF)
4196 0 : return NS_OK;//nothing to do we cannot affect selection from here
4197 :
4198 : #ifdef XP_MACOSX
4199 : if (mouseEvent->IsControl())
4200 : return NS_OK;//short circuit. hard coded for mac due to time restraints.
4201 : bool control = mouseEvent->IsMeta();
4202 : #else
4203 : bool control = mouseEvent->IsControl();
4204 0 : #endif
4205 :
4206 : RefPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection);
4207 0 : if (mouseEvent->mClickCount > 1) {
4208 0 : // These methods aren't const but can't actually delete anything,
4209 : // so no need for AutoWeakFrame.
4210 : fc->SetDragState(true);
4211 0 : fc->SetMouseDoubleDown(true);
4212 0 : return HandleMultiplePress(aPresContext, mouseEvent, aEventStatus, control);
4213 0 : }
4214 :
4215 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
4216 0 : ContentOffsets offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
4217 0 :
4218 : if (!offsets.content)
4219 0 : return NS_ERROR_FAILURE;
4220 :
4221 : // Let Ctrl/Cmd+mouse down do table selection instead of drag initiation
4222 : nsCOMPtr<nsIContent>parentContent;
4223 0 : int32_t contentOffset;
4224 : TableSelection target;
4225 : nsresult rv;
4226 : rv = GetDataForTableSelection(frameselection, shell, mouseEvent,
4227 0 : getter_AddRefs(parentContent), &contentOffset,
4228 0 : &target);
4229 0 : if (NS_SUCCEEDED(rv) && parentContent)
4230 0 : {
4231 : fc->SetDragState(true);
4232 0 : return fc->HandleTableSelection(parentContent, contentOffset, target,
4233 0 : mouseEvent);
4234 0 : }
4235 :
4236 : fc->SetDelayedCaretData(0);
4237 0 :
4238 : // Check if any part of this frame is selected, and if the
4239 : // user clicked inside the selected region. If so, we delay
4240 : // starting a new selection since the user may be trying to
4241 : // drag the selected region to some other app.
4242 :
4243 : if (GetContent() && GetContent()->IsSelectionDescendant())
4244 0 : {
4245 : bool inSelection = false;
4246 0 : UniquePtr<SelectionDetails> details
4247 : = frameselection->LookUpSelection(offsets.content, 0,
4248 : offsets.EndOffset(), false);
4249 0 :
4250 : //
4251 : // If there are any details, check to see if the user clicked
4252 : // within any selected region of the frame.
4253 : //
4254 :
4255 : for (SelectionDetails* curDetail = details.get();
4256 0 : curDetail;
4257 0 : curDetail = curDetail->mNext.get()) {
4258 0 : //
4259 : // If the user clicked inside a selection, then just
4260 : // return without doing anything. We will handle placing
4261 : // the caret later on when the mouse is released. We ignore
4262 : // the spellcheck, find and url formatting selections.
4263 : //
4264 : if (curDetail->mSelectionType != SelectionType::eSpellCheck &&
4265 0 : curDetail->mSelectionType != SelectionType::eFind &&
4266 0 : curDetail->mSelectionType != SelectionType::eURLSecondary &&
4267 0 : curDetail->mSelectionType != SelectionType::eURLStrikeout &&
4268 0 : curDetail->mStart <= offsets.StartOffset() &&
4269 0 : offsets.EndOffset() <= curDetail->mEnd)
4270 0 : {
4271 : inSelection = true;
4272 0 : }
4273 : }
4274 :
4275 : if (inSelection) {
4276 0 : fc->SetDragState(false);
4277 0 : fc->SetDelayedCaretData(mouseEvent);
4278 0 : return NS_OK;
4279 0 : }
4280 : }
4281 :
4282 : fc->SetDragState(true);
4283 0 :
4284 : // Do not touch any nsFrame members after this point without adding
4285 : // weakFrame checks.
4286 : rv = fc->HandleClick(offsets.content, offsets.StartOffset(),
4287 0 : offsets.EndOffset(), mouseEvent->IsShift(), control,
4288 0 : offsets.associate);
4289 0 :
4290 : if (NS_FAILED(rv))
4291 0 : return rv;
4292 :
4293 : if (offsets.offset != offsets.secondaryOffset)
4294 0 : fc->MaintainSelection();
4295 0 :
4296 : if (isEditor && !mouseEvent->IsShift() &&
4297 0 : (offsets.EndOffset() - offsets.StartOffset()) == 1)
4298 0 : {
4299 : // A single node is selected and we aren't extending an existing
4300 : // selection, which means the user clicked directly on an object (either
4301 : // -moz-user-select: all or a non-text node without children).
4302 : // Therefore, disable selection extension during mouse moves.
4303 : // XXX This is a bit hacky; shouldn't editor be able to deal with this?
4304 : fc->SetDragState(false);
4305 0 : }
4306 :
4307 : return rv;
4308 : }
4309 :
4310 : /*
4311 : * SelectByTypeAtPoint
4312 : *
4313 : * Search for selectable content at point and attempt to select
4314 : * based on the start and end selection behaviours.
4315 : *
4316 : * @param aPresContext Presentation context
4317 : * @param aPoint Point at which selection will occur. Coordinates
4318 : * should be relaitve to this frame.
4319 : * @param aBeginAmountType, aEndAmountType Selection behavior, see
4320 : * nsIFrame for definitions.
4321 : * @param aSelectFlags Selection flags defined in nsFame.h.
4322 : * @return success or failure at finding suitable content to select.
4323 : */
4324 : nsresult
4325 : nsFrame::SelectByTypeAtPoint(nsPresContext* aPresContext,
4326 0 : const nsPoint& aPoint,
4327 : nsSelectionAmount aBeginAmountType,
4328 : nsSelectionAmount aEndAmountType,
4329 : uint32_t aSelectFlags)
4330 : {
4331 : NS_ENSURE_ARG_POINTER(aPresContext);
4332 0 :
4333 : // No point in selecting if selection is turned off
4334 : if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF)
4335 0 : return NS_OK;
4336 :
4337 : ContentOffsets offsets = GetContentOffsetsFromPoint(aPoint, SKIP_HIDDEN);
4338 0 : if (!offsets.content)
4339 0 : return NS_ERROR_FAILURE;
4340 :
4341 : int32_t offset;
4342 : const nsFrameSelection* frameSelection =
4343 : PresContext()->GetPresShell()->ConstFrameSelection();
4344 0 : nsIFrame* theFrame = frameSelection->
4345 : GetFrameForNodeOffset(offsets.content, offsets.offset,
4346 0 : offsets.associate, &offset);
4347 0 : if (!theFrame)
4348 0 : return NS_ERROR_FAILURE;
4349 :
4350 : nsFrame* frame = static_cast<nsFrame*>(theFrame);
4351 0 : return frame->PeekBackwardAndForward(aBeginAmountType, aEndAmountType, offset,
4352 0 : aBeginAmountType != eSelectWord,
4353 : aSelectFlags);
4354 0 : }
4355 :
4356 : /**
4357 : * Multiple Mouse Press -- line or paragraph selection -- for the frame.
4358 : * Wouldn't it be nice if this didn't have to be hardwired into Frame code?
4359 : */
4360 : NS_IMETHODIMP
4361 : nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
4362 0 : WidgetGUIEvent* aEvent,
4363 : nsEventStatus* aEventStatus,
4364 : bool aControlHeld)
4365 : {
4366 : NS_ENSURE_ARG_POINTER(aEvent);
4367 0 : NS_ENSURE_ARG_POINTER(aEventStatus);
4368 0 :
4369 : if (nsEventStatus_eConsumeNoDefault == *aEventStatus ||
4370 0 : DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
4371 0 : return NS_OK;
4372 : }
4373 :
4374 : // Find out whether we're doing line or paragraph selection.
4375 : // If browser.triple_click_selects_paragraph is true, triple-click selects paragraph.
4376 : // Otherwise, triple-click selects line, and quadruple-click selects paragraph
4377 : // (on platforms that support quadruple-click).
4378 : nsSelectionAmount beginAmount, endAmount;
4379 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
4380 0 : if (!mouseEvent) {
4381 0 : return NS_OK;
4382 : }
4383 :
4384 : if (mouseEvent->mClickCount == 4) {
4385 0 : beginAmount = endAmount = eSelectParagraph;
4386 : } else if (mouseEvent->mClickCount == 3) {
4387 0 : if (Preferences::GetBool("browser.triple_click_selects_paragraph")) {
4388 0 : beginAmount = endAmount = eSelectParagraph;
4389 : } else {
4390 : beginAmount = eSelectBeginLine;
4391 0 : endAmount = eSelectEndLine;
4392 0 : }
4393 : } else if (mouseEvent->mClickCount == 2) {
4394 0 : // We only want inline frames; PeekBackwardAndForward dislikes blocks
4395 : beginAmount = endAmount = eSelectWord;
4396 : } else {
4397 : return NS_OK;
4398 : }
4399 :
4400 : nsPoint relPoint =
4401 : nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
4402 0 : return SelectByTypeAtPoint(aPresContext, relPoint, beginAmount, endAmount,
4403 0 : (aControlHeld ? SELECT_ACCUMULATE : 0));
4404 0 : }
4405 :
4406 : nsresult
4407 : nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
4408 0 : nsSelectionAmount aAmountForward,
4409 : int32_t aStartPos,
4410 : bool aJumpLines,
4411 : uint32_t aSelectFlags)
4412 : {
4413 : nsIFrame* baseFrame = this;
4414 0 : int32_t baseOffset = aStartPos;
4415 0 : nsresult rv;
4416 :
4417 : if (aAmountBack == eSelectWord) {
4418 0 : // To avoid selecting the previous word when at start of word,
4419 : // first move one character forward.
4420 : nsPeekOffsetStruct pos(eSelectCharacter,
4421 : eDirNext,
4422 : aStartPos,
4423 : nsPoint(0, 0),
4424 0 : aJumpLines,
4425 : true, //limit on scrolled views
4426 : false,
4427 : false,
4428 : false);
4429 0 : rv = PeekOffset(&pos);
4430 0 : if (NS_SUCCEEDED(rv)) {
4431 0 : baseFrame = pos.mResultFrame;
4432 0 : baseOffset = pos.mContentOffset;
4433 0 : }
4434 : }
4435 :
4436 : // Use peek offset one way then the other:
4437 : nsPeekOffsetStruct startpos(aAmountBack,
4438 : eDirPrevious,
4439 : baseOffset,
4440 : nsPoint(0, 0),
4441 0 : aJumpLines,
4442 : true, //limit on scrolled views
4443 : false,
4444 : false,
4445 : false);
4446 0 : rv = baseFrame->PeekOffset(&startpos);
4447 0 : if (NS_FAILED(rv))
4448 0 : return rv;
4449 :
4450 : nsPeekOffsetStruct endpos(aAmountForward,
4451 : eDirNext,
4452 : aStartPos,
4453 : nsPoint(0, 0),
4454 0 : aJumpLines,
4455 : true, //limit on scrolled views
4456 : false,
4457 : false,
4458 : false);
4459 0 : rv = PeekOffset(&endpos);
4460 0 : if (NS_FAILED(rv))
4461 0 : return rv;
4462 :
4463 : // Keep frameSelection alive.
4464 : RefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
4465 0 :
4466 : rv = frameSelection->HandleClick(startpos.mResultContent,
4467 0 : startpos.mContentOffset, startpos.mContentOffset,
4468 0 : false, (aSelectFlags & SELECT_ACCUMULATE),
4469 0 : CARET_ASSOCIATE_AFTER);
4470 0 : if (NS_FAILED(rv))
4471 0 : return rv;
4472 :
4473 : rv = frameSelection->HandleClick(endpos.mResultContent,
4474 0 : endpos.mContentOffset, endpos.mContentOffset,
4475 0 : true, false,
4476 : CARET_ASSOCIATE_BEFORE);
4477 0 : if (NS_FAILED(rv))
4478 0 : return rv;
4479 :
4480 : // maintain selection
4481 : return frameSelection->MaintainSelection(aAmountBack);
4482 0 : }
4483 :
4484 : NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext,
4485 0 : WidgetGUIEvent* aEvent,
4486 : nsEventStatus* aEventStatus)
4487 : {
4488 : MOZ_ASSERT(aEvent->mClass == eMouseEventClass,
4489 0 : "HandleDrag can only handle mouse event");
4490 :
4491 : RefPtr<nsFrameSelection> frameselection = GetFrameSelection();
4492 0 : bool mouseDown = frameselection->GetDragState();
4493 0 : if (!mouseDown) {
4494 0 : return NS_OK;
4495 : }
4496 :
4497 : nsIFrame* scrollbar =
4498 : nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::Scrollbar);
4499 0 : if (!scrollbar) {
4500 0 : // XXX Do we really need to exclude non-selectable content here?
4501 : // GetContentOffsetsFromPoint can handle it just fine, although some
4502 : // other stuff might not like it.
4503 : // NOTE: DisplaySelection() returns SELECTION_OFF for non-selectable frames.
4504 : if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
4505 0 : return NS_OK;
4506 : }
4507 : }
4508 :
4509 : frameselection->StopAutoScrollTimer();
4510 0 :
4511 : // Check if we are dragging in a table cell
4512 : nsCOMPtr<nsIContent> parentContent;
4513 0 : int32_t contentOffset;
4514 : TableSelection target;
4515 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
4516 0 : nsCOMPtr<nsIPresShell> presShell = aPresContext->PresShell();
4517 0 : nsresult result;
4518 : result = GetDataForTableSelection(frameselection, presShell, mouseEvent,
4519 0 : getter_AddRefs(parentContent),
4520 0 : &contentOffset, &target);
4521 0 :
4522 : AutoWeakFrame weakThis = this;
4523 0 : if (NS_SUCCEEDED(result) && parentContent) {
4524 0 : frameselection->HandleTableSelection(parentContent, contentOffset, target,
4525 0 : mouseEvent);
4526 0 : } else {
4527 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
4528 0 : frameselection->HandleDrag(this, pt);
4529 0 : }
4530 :
4531 : // The frameselection object notifies selection listeners synchronously above
4532 : // which might have killed us.
4533 : if (!weakThis.IsAlive()) {
4534 0 : return NS_OK;
4535 : }
4536 :
4537 : // get the nearest scrollframe
4538 : nsIScrollableFrame* scrollFrame =
4539 : nsLayoutUtils::GetNearestScrollableFrame(this,
4540 : nsLayoutUtils::SCROLLABLE_SAME_DOC |
4541 : nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4542 0 :
4543 : if (scrollFrame) {
4544 0 : nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame();
4545 0 : if (capturingFrame) {
4546 0 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent,
4547 : capturingFrame);
4548 0 : frameselection->StartAutoScrollTimer(capturingFrame, pt, 30);
4549 0 : }
4550 : }
4551 :
4552 : return NS_OK;
4553 : }
4554 :
4555 : /**
4556 : * This static method handles part of the nsFrame::HandleRelease in a way
4557 : * which doesn't rely on the nsFrame object to stay alive.
4558 : */
4559 : static nsresult
4560 : HandleFrameSelection(nsFrameSelection* aFrameSelection,
4561 0 : nsIFrame::ContentOffsets& aOffsets,
4562 : bool aHandleTableSel,
4563 : int32_t aContentOffsetForTableSel,
4564 : TableSelection aTargetForTableSel,
4565 : nsIContent* aParentContentForTableSel,
4566 : WidgetGUIEvent* aEvent,
4567 : nsEventStatus* aEventStatus)
4568 : {
4569 : if (!aFrameSelection) {
4570 0 : return NS_OK;
4571 : }
4572 :
4573 : nsresult rv = NS_OK;
4574 0 :
4575 : if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
4576 0 : if (!aHandleTableSel) {
4577 0 : if (!aOffsets.content || !aFrameSelection->HasDelayedCaretData()) {
4578 0 : return NS_ERROR_FAILURE;
4579 : }
4580 :
4581 : // We are doing this to simulate what we would have done on HandlePress.
4582 : // We didn't do it there to give the user an opportunity to drag
4583 : // the text, but since they didn't drag, we want to place the
4584 : // caret.
4585 : // However, we'll use the mouse position from the release, since:
4586 : // * it's easier
4587 : // * that's the normal click position to use (although really, in
4588 : // the normal case, small movements that don't count as a drag
4589 : // can do selection)
4590 : aFrameSelection->SetDragState(true);
4591 0 :
4592 : rv = aFrameSelection->HandleClick(aOffsets.content,
4593 0 : aOffsets.StartOffset(),
4594 0 : aOffsets.EndOffset(),
4595 0 : aFrameSelection->IsShiftDownInDelayedCaretData(),
4596 0 : false,
4597 : aOffsets.associate);
4598 0 : if (NS_FAILED(rv)) {
4599 0 : return rv;
4600 : }
4601 : } else if (aParentContentForTableSel) {
4602 0 : aFrameSelection->SetDragState(false);
4603 0 : rv = aFrameSelection->HandleTableSelection(
4604 0 : aParentContentForTableSel,
4605 : aContentOffsetForTableSel,
4606 : aTargetForTableSel,
4607 : aEvent->AsMouseEvent());
4608 0 : if (NS_FAILED(rv)) {
4609 0 : return rv;
4610 : }
4611 : }
4612 : aFrameSelection->SetDelayedCaretData(0);
4613 0 : }
4614 :
4615 : aFrameSelection->SetDragState(false);
4616 0 : aFrameSelection->StopAutoScrollTimer();
4617 0 :
4618 : return NS_OK;
4619 0 : }
4620 :
4621 : NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
4622 0 : WidgetGUIEvent* aEvent,
4623 : nsEventStatus* aEventStatus)
4624 : {
4625 : if (aEvent->mClass != eMouseEventClass) {
4626 0 : return NS_OK;
4627 : }
4628 :
4629 : nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
4630 0 :
4631 : nsCOMPtr<nsIContent> captureContent = nsIPresShell::GetCapturingContent();
4632 0 :
4633 : // We can unconditionally stop capturing because
4634 : // we should never be capturing when the mouse button is up
4635 : nsIPresShell::SetCapturingContent(nullptr, 0);
4636 0 :
4637 : bool selectionOff =
4638 : (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
4639 0 :
4640 : RefPtr<nsFrameSelection> frameselection;
4641 0 : ContentOffsets offsets;
4642 0 : nsCOMPtr<nsIContent> parentContent;
4643 0 : int32_t contentOffsetForTableSel = 0;
4644 0 : TableSelection targetForTableSel = TableSelection::None;
4645 0 : bool handleTableSelection = true;
4646 0 :
4647 : if (!selectionOff) {
4648 0 : frameselection = GetFrameSelection();
4649 0 : if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) {
4650 0 : // Check if the frameselection recorded the mouse going down.
4651 : // If not, the user must have clicked in a part of the selection.
4652 : // Place the caret before continuing!
4653 :
4654 : if (frameselection->MouseDownRecorded()) {
4655 0 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
4656 0 : offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
4657 0 : handleTableSelection = false;
4658 0 : } else {
4659 : GetDataForTableSelection(frameselection, PresShell(),
4660 0 : aEvent->AsMouseEvent(),
4661 0 : getter_AddRefs(parentContent),
4662 0 : &contentOffsetForTableSel,
4663 : &targetForTableSel);
4664 0 : }
4665 : }
4666 : }
4667 :
4668 : // We might be capturing in some other document and the event just happened to
4669 : // trickle down here. Make sure that document's frame selection is notified.
4670 : // Note, this may cause the current nsFrame object to be deleted, bug 336592.
4671 : RefPtr<nsFrameSelection> frameSelection;
4672 0 : if (activeFrame != this &&
4673 0 : static_cast<nsFrame*>(activeFrame)->DisplaySelection(activeFrame->PresContext())
4674 0 : != nsISelectionController::SELECTION_OFF) {
4675 : frameSelection = activeFrame->GetFrameSelection();
4676 0 : }
4677 :
4678 : // Also check the selection of the capturing content which might be in a
4679 : // different document.
4680 : if (!frameSelection && captureContent) {
4681 0 : nsIDocument* doc = captureContent->GetUncomposedDoc();
4682 0 : if (doc) {
4683 0 : nsIPresShell* capturingShell = doc->GetShell();
4684 0 : if (capturingShell && capturingShell != PresContext()->GetPresShell()) {
4685 0 : frameSelection = capturingShell->FrameSelection();
4686 0 : }
4687 : }
4688 : }
4689 :
4690 : if (frameSelection) {
4691 0 : frameSelection->SetDragState(false);
4692 0 : frameSelection->StopAutoScrollTimer();
4693 0 : nsIScrollableFrame* scrollFrame =
4694 : nsLayoutUtils::GetNearestScrollableFrame(this,
4695 : nsLayoutUtils::SCROLLABLE_SAME_DOC |
4696 : nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4697 0 : if (scrollFrame) {
4698 0 : // Perform any additional scrolling needed to maintain CSS snap point
4699 : // requirements when autoscrolling is over.
4700 : scrollFrame->ScrollSnap();
4701 0 : }
4702 : }
4703 :
4704 : // Do not call any methods of the current object after this point!!!
4705 : // The object is perhaps dead!
4706 :
4707 : return selectionOff
4708 : ? NS_OK
4709 0 : : HandleFrameSelection(frameselection, offsets, handleTableSelection,
4710 0 : contentOffsetForTableSel, targetForTableSel,
4711 : parentContent, aEvent, aEventStatus);
4712 : }
4713 :
4714 : struct MOZ_STACK_CLASS FrameContentRange {
4715 0 : FrameContentRange(nsIContent* aContent, int32_t aStart, int32_t aEnd) :
4716 : content(aContent), start(aStart), end(aEnd) { }
4717 0 : nsCOMPtr<nsIContent> content;
4718 : int32_t start;
4719 : int32_t end;
4720 : };
4721 :
4722 : // Retrieve the content offsets of a frame
4723 : static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
4724 0 : nsIContent* content = aFrame->GetContent();
4725 0 : if (!content) {
4726 0 : NS_WARNING("Frame has no content");
4727 0 : return FrameContentRange(nullptr, -1, -1);
4728 : }
4729 :
4730 : LayoutFrameType type = aFrame->Type();
4731 0 : if (type == LayoutFrameType::Text) {
4732 0 : int32_t offset, offsetEnd;
4733 : aFrame->GetOffsets(offset, offsetEnd);
4734 0 : return FrameContentRange(content, offset, offsetEnd);
4735 0 : }
4736 :
4737 : if (type == LayoutFrameType::Br) {
4738 0 : nsIContent* parent = content->GetParent();
4739 0 : int32_t beginOffset = parent->ComputeIndexOf(content);
4740 0 : return FrameContentRange(parent, beginOffset, beginOffset);
4741 : }
4742 :
4743 : while (content->IsRootOfAnonymousSubtree()) {
4744 0 : content = content->GetParent();
4745 0 : }
4746 :
4747 : nsIContent* parent = content->GetParent();
4748 0 : if (nsLayoutUtils::GetAsBlock(aFrame) || !parent) {
4749 0 : return FrameContentRange(content, 0, content->GetChildCount());
4750 0 : }
4751 :
4752 : // TODO(emilio): Revise this in presence of Shadow DOM / display: contents,
4753 : // it's likely that we don't want to just walk the light tree, and we need to
4754 : // change the representation of FrameContentRange.
4755 : int32_t index = parent->ComputeIndexOf(content);
4756 0 : MOZ_ASSERT(index >= 0);
4757 0 : return FrameContentRange(parent, index, index + 1);
4758 0 : }
4759 :
4760 : // The FrameTarget represents the closest frame to a point that can be selected
4761 : // The frame is the frame represented, frameEdge says whether one end of the
4762 : // frame is the result (in which case different handling is needed), and
4763 : // afterFrame says which end is repersented if frameEdge is true
4764 : struct FrameTarget {
4765 : FrameTarget(nsIFrame* aFrame, bool aFrameEdge, bool aAfterFrame)
4766 : : frame(aFrame)
4767 : , frameEdge(aFrameEdge)
4768 : , afterFrame(aAfterFrame)
4769 0 : {}
4770 :
4771 : static FrameTarget Null() {
4772 : return FrameTarget(nullptr, false, false);
4773 0 : }
4774 :
4775 : bool IsNull() {
4776 : return !frame;
4777 : }
4778 : nsIFrame* frame;
4779 : bool frameEdge;
4780 : bool afterFrame;
4781 : };
4782 :
4783 : // See function implementation for information
4784 : static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame,
4785 : const nsPoint& aPoint,
4786 : uint32_t aFlags);
4787 :
4788 : static bool SelfIsSelectable(nsIFrame* aFrame, uint32_t aFlags)
4789 0 : {
4790 : if ((aFlags & nsIFrame::SKIP_HIDDEN) &&
4791 0 : !aFrame->StyleVisibility()->IsVisible()) {
4792 0 : return false;
4793 : }
4794 : return !aFrame->IsGeneratedContentFrame() &&
4795 0 : aFrame->StyleUIReset()->mUserSelect != StyleUserSelect::None;
4796 0 : }
4797 :
4798 : static bool SelectionDescendToKids(nsIFrame* aFrame) {
4799 0 : StyleUserSelect style = aFrame->StyleUIReset()->mUserSelect;
4800 0 : nsIFrame* parent = aFrame->GetParent();
4801 0 : // If we are only near (not directly over) then don't traverse
4802 : // frames with independent selection (e.g. text and list controls)
4803 : // unless we're already inside such a frame (see bug 268497). Note that this
4804 : // prevents any of the users of this method from entering form controls.
4805 : // XXX We might want some way to allow using the up-arrow to go into a form
4806 : // control, but the focus didn't work right anyway; it'd probably be enough
4807 : // if the left and right arrows could enter textboxes (which I don't believe
4808 : // they can at the moment)
4809 : return !aFrame->IsGeneratedContentFrame() &&
4810 0 : style != StyleUserSelect::All &&
4811 0 : style != StyleUserSelect::None &&
4812 0 : ((parent->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
4813 0 : !(aFrame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION));
4814 0 : }
4815 :
4816 : static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild,
4817 0 : const nsPoint& aPoint,
4818 : uint32_t aFlags)
4819 : {
4820 : nsIFrame* parent = aChild->GetParent();
4821 0 : if (SelectionDescendToKids(aChild)) {
4822 0 : nsPoint pt = aPoint - aChild->GetOffsetTo(parent);
4823 0 : return GetSelectionClosestFrame(aChild, pt, aFlags);
4824 0 : }
4825 : return FrameTarget(aChild, false, false);
4826 0 : }
4827 :
4828 : // When the cursor needs to be at the beginning of a block, it shouldn't be
4829 : // before the first child. A click on a block whose first child is a block
4830 : // should put the cursor in the child. The cursor shouldn't be between the
4831 : // blocks, because that's not where it's expected.
4832 : // Note that this method is guaranteed to succeed.
4833 : static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
4834 0 : bool aEndFrame, uint32_t aFlags) {
4835 : if (SelectionDescendToKids(aFrame)) {
4836 0 : nsIFrame* result = nullptr;
4837 0 : nsIFrame *frame = aFrame->PrincipalChildList().FirstChild();
4838 0 : if (!aEndFrame) {
4839 0 : while (frame && (!SelfIsSelectable(frame, aFlags) ||
4840 0 : frame->IsEmpty()))
4841 0 : frame = frame->GetNextSibling();
4842 0 : if (frame)
4843 0 : result = frame;
4844 0 : } else {
4845 : // Because the frame tree is singly linked, to find the last frame,
4846 : // we have to iterate through all the frames
4847 : // XXX I have a feeling this could be slow for long blocks, although
4848 : // I can't find any slowdowns
4849 : while (frame) {
4850 0 : if (!frame->IsEmpty() && SelfIsSelectable(frame, aFlags))
4851 0 : result = frame;
4852 0 : frame = frame->GetNextSibling();
4853 0 : }
4854 : }
4855 : if (result)
4856 0 : return DrillDownToSelectionFrame(result, aEndFrame, aFlags);
4857 0 : }
4858 : // If the current frame has no targetable children, target the current frame
4859 : return FrameTarget(aFrame, true, aEndFrame);
4860 0 : }
4861 :
4862 : // This method finds the closest valid FrameTarget on a given line; if there is
4863 : // no valid FrameTarget on the line, it returns a null FrameTarget
4864 : static FrameTarget GetSelectionClosestFrameForLine(
4865 0 : nsBlockFrame* aParent,
4866 : nsBlockFrame::LineIterator aLine,
4867 : const nsPoint& aPoint,
4868 : uint32_t aFlags)
4869 : {
4870 : // Account for end of lines (any iterator from the block is valid)
4871 : if (aLine == aParent->LinesEnd())
4872 0 : return DrillDownToSelectionFrame(aParent, true, aFlags);
4873 0 : nsIFrame* frame = aLine->mFirstChild;
4874 0 : nsIFrame* closestFromIStart = nullptr;
4875 0 : nsIFrame* closestFromIEnd = nullptr;
4876 0 : nscoord closestIStart = aLine->IStart(), closestIEnd = aLine->IEnd();
4877 0 : WritingMode wm = aLine->mWritingMode;
4878 0 : LogicalPoint pt(wm, aPoint, aLine->mContainerSize);
4879 0 : bool canSkipBr = false;
4880 0 : for (int32_t n = aLine->GetChildCount(); n;
4881 0 : --n, frame = frame->GetNextSibling()) {
4882 : // Skip brFrames. Can only skip if the line contains at least
4883 : // one selectable and non-empty frame before
4884 : if (!SelfIsSelectable(frame, aFlags) || frame->IsEmpty() ||
4885 0 : (canSkipBr && frame->IsBrFrame())) {
4886 0 : continue;
4887 0 : }
4888 : canSkipBr = true;
4889 0 : LogicalRect frameRect = LogicalRect(wm, frame->GetRect(),
4890 0 : aLine->mContainerSize);
4891 0 : if (pt.I(wm) >= frameRect.IStart(wm)) {
4892 0 : if (pt.I(wm) < frameRect.IEnd(wm)) {
4893 0 : return GetSelectionClosestFrameForChild(frame, aPoint, aFlags);
4894 0 : }
4895 : if (frameRect.IEnd(wm) >= closestIStart) {
4896 0 : closestFromIStart = frame;
4897 0 : closestIStart = frameRect.IEnd(wm);
4898 0 : }
4899 : } else {
4900 : if (frameRect.IStart(wm) <= closestIEnd) {
4901 0 : closestFromIEnd = frame;
4902 0 : closestIEnd = frameRect.IStart(wm);
4903 0 : }
4904 : }
4905 : }
4906 : if (!closestFromIStart && !closestFromIEnd) {
4907 0 : // We should only get here if there are no selectable frames on a line
4908 : // XXX Do we need more elaborate handling here?
4909 : return FrameTarget::Null();
4910 : }
4911 : if (closestFromIStart &&
4912 0 : (!closestFromIEnd ||
4913 0 : (abs(pt.I(wm) - closestIStart) <= abs(pt.I(wm) - closestIEnd)))) {
4914 0 : return GetSelectionClosestFrameForChild(closestFromIStart, aPoint,
4915 : aFlags);
4916 0 : }
4917 : return GetSelectionClosestFrameForChild(closestFromIEnd, aPoint, aFlags);
4918 0 : }
4919 :
4920 : // This method is for the special handling we do for block frames; they're
4921 : // special because they represent paragraphs and because they are organized
4922 : // into lines, which have bounds that are not stored elsewhere in the
4923 : // frame tree. Returns a null FrameTarget for frames which are not
4924 : // blocks or blocks with no lines except editable one.
4925 : static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
4926 0 : const nsPoint& aPoint,
4927 : uint32_t aFlags)
4928 : {
4929 : nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(aFrame); // used only for QI
4930 0 : if (!bf)
4931 0 : return FrameTarget::Null();
4932 :
4933 : // This code searches for the correct line
4934 : nsBlockFrame::LineIterator end = bf->LinesEnd();
4935 0 : nsBlockFrame::LineIterator curLine = bf->LinesBegin();
4936 0 : nsBlockFrame::LineIterator closestLine = end;
4937 0 :
4938 : if (curLine != end) {
4939 0 : // Convert aPoint into a LogicalPoint in the writing-mode of this block
4940 : WritingMode wm = curLine->mWritingMode;
4941 0 : LogicalPoint pt(wm, aPoint, curLine->mContainerSize);
4942 0 : do {
4943 0 : // Check to see if our point lies within the line's block-direction bounds
4944 : nscoord BCoord = pt.B(wm) - curLine->BStart();
4945 0 : nscoord BSize = curLine->BSize();
4946 0 : if (BCoord >= 0 && BCoord < BSize) {
4947 0 : closestLine = curLine;
4948 : break; // We found the line; stop looking
4949 : }
4950 : if (BCoord < 0)
4951 0 : break;
4952 : ++curLine;
4953 0 : } while (curLine != end);
4954 :
4955 : if (closestLine == end) {
4956 0 : nsBlockFrame::LineIterator prevLine = curLine.prev();
4957 0 : nsBlockFrame::LineIterator nextLine = curLine;
4958 0 : // Avoid empty lines
4959 : while (nextLine != end && nextLine->IsEmpty())
4960 0 : ++nextLine;
4961 : while (prevLine != end && prevLine->IsEmpty())
4962 0 : --prevLine;
4963 :
4964 : // This hidden pref dictates whether a point above or below all lines comes
4965 : // up with a line or the beginning or end of the frame; 0 on Windows,
4966 : // 1 on other platforms by default at the writing of this code
4967 : int32_t dragOutOfFrame =
4968 : Preferences::GetInt("browser.drag_out_of_frame_style");
4969 0 :
4970 : if (prevLine == end) {
4971 0 : if (dragOutOfFrame == 1 || nextLine == end)
4972 0 : return DrillDownToSelectionFrame(aFrame, false, aFlags);
4973 0 : closestLine = nextLine;
4974 : } else if (nextLine == end) {
4975 0 : if (dragOutOfFrame == 1)
4976 0 : return DrillDownToSelectionFrame(aFrame, true, aFlags);
4977 0 : closestLine = prevLine;
4978 : } else { // Figure out which line is closer
4979 : if (pt.B(wm) - prevLine->BEnd() < nextLine->BStart() - pt.B(wm))
4980 0 : closestLine = prevLine;
4981 : else
4982 : closestLine = nextLine;
4983 : }
4984 : }
4985 : }
4986 :
4987 : do {
4988 0 : FrameTarget target = GetSelectionClosestFrameForLine(bf, closestLine,
4989 : aPoint, aFlags);
4990 0 : if (!target.IsNull())
4991 0 : return target;
4992 0 : ++closestLine;
4993 0 : } while (closestLine != end);
4994 :
4995 : // Fall back to just targeting the last targetable place
4996 : return DrillDownToSelectionFrame(aFrame, true, aFlags);
4997 0 : }
4998 :
4999 : // GetSelectionClosestFrame is the helper function that calculates the closest
5000 : // frame to the given point.
5001 : // It doesn't completely account for offset styles, so needs to be used in
5002 : // restricted environments.
5003 : // Cannot handle overlapping frames correctly, so it should receive the output
5004 : // of GetFrameForPoint
5005 : // Guaranteed to return a valid FrameTarget
5006 : static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame,
5007 0 : const nsPoint& aPoint,
5008 : uint32_t aFlags)
5009 : {
5010 : {
5011 : // Handle blocks; if the frame isn't a block, the method fails
5012 : FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint, aFlags);
5013 0 : if (!target.IsNull())
5014 0 : return target;
5015 0 : }
5016 :
5017 : nsIFrame *kid = aFrame->PrincipalChildList().FirstChild();
5018 0 :
5019 : if (kid) {
5020 0 : // Go through all the child frames to find the closest one
5021 : nsIFrame::FrameWithDistance closest = { nullptr, nscoord_MAX, nscoord_MAX };
5022 0 : for (; kid; kid = kid->GetNextSibling()) {
5023 0 : if (!SelfIsSelectable(kid, aFlags) || kid->IsEmpty())
5024 0 : continue;
5025 :
5026 : kid->FindCloserFrameForSelection(aPoint, &closest);
5027 0 : }
5028 : if (closest.mFrame) {
5029 0 : if (nsSVGUtils::IsInSVGTextSubtree(closest.mFrame))
5030 0 : return FrameTarget(closest.mFrame, false, false);
5031 0 : return GetSelectionClosestFrameForChild(closest.mFrame, aPoint, aFlags);
5032 0 : }
5033 : }
5034 : return FrameTarget(aFrame, false, false);
5035 0 : }
5036 :
5037 : static nsIFrame::ContentOffsets
5038 : OffsetsForSingleFrame(nsIFrame* aFrame, const nsPoint& aPoint)
5039 0 : {
5040 : nsIFrame::ContentOffsets offsets;
5041 0 : FrameContentRange range = GetRangeForFrame(aFrame);
5042 0 : offsets.content = range.content;
5043 0 : // If there are continuations (meaning it's not one rectangle), this is the
5044 : // best this function can do
5045 : if (aFrame->GetNextContinuation() || aFrame->GetPrevContinuation()) {
5046 0 : offsets.offset = range.start;
5047 0 : offsets.secondaryOffset = range.end;
5048 0 : offsets.associate = CARET_ASSOCIATE_AFTER;
5049 0 : return offsets;
5050 0 : }
5051 :
5052 : // Figure out whether the offsets should be over, after, or before the frame
5053 : nsRect rect(nsPoint(0, 0), aFrame->GetSize());
5054 0 :
5055 : bool isBlock = aFrame->GetDisplay() != StyleDisplay::Inline;
5056 0 : bool isRtl = (aFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL);
5057 0 : if ((isBlock && rect.y < aPoint.y) ||
5058 0 : (!isBlock && ((isRtl && rect.x + rect.width / 2 > aPoint.x) ||
5059 0 : (!isRtl && rect.x + rect.width / 2 < aPoint.x)))) {
5060 0 : offsets.offset = range.end;
5061 0 : if (rect.Contains(aPoint))
5062 0 : offsets.secondaryOffset = range.start;
5063 0 : else
5064 : offsets.secondaryOffset = range.end;
5065 0 : } else {
5066 : offsets.offset = range.start;
5067 0 : if (rect.Contains(aPoint))
5068 0 : offsets.secondaryOffset = range.end;
5069 0 : else
5070 : offsets.secondaryOffset = range.start;
5071 0 : }
5072 : offsets.associate =
5073 0 : offsets.offset == range.start ? CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
5074 0 : return offsets;
5075 : }
5076 :
5077 : static nsIFrame* AdjustFrameForSelectionStyles(nsIFrame* aFrame) {
5078 0 : nsIFrame* adjustedFrame = aFrame;
5079 0 : for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent())
5080 0 : {
5081 : // These are the conditions that make all children not able to handle
5082 : // a cursor.
5083 : StyleUserSelect userSelect = frame->StyleUIReset()->mUserSelect;
5084 0 : if (userSelect == StyleUserSelect::MozText) {
5085 0 : // If we see a -moz-text element, we shouldn't look further up the parent
5086 : // chain!
5087 : break;
5088 : }
5089 : if (userSelect == StyleUserSelect::All ||
5090 0 : frame->IsGeneratedContentFrame()) {
5091 0 : adjustedFrame = frame;
5092 0 : }
5093 : }
5094 : return adjustedFrame;
5095 0 : }
5096 :
5097 : nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(const nsPoint& aPoint,
5098 0 : uint32_t aFlags)
5099 : {
5100 : nsIFrame *adjustedFrame;
5101 : if (aFlags & IGNORE_SELECTION_STYLE) {
5102 0 : adjustedFrame = this;
5103 : }
5104 : else {
5105 : // This section of code deals with special selection styles. Note that
5106 : // -moz-all exists, even though it doesn't need to be explicitly handled.
5107 : //
5108 : // The offset is forced not to end up in generated content; content offsets
5109 : // cannot represent content outside of the document's content tree.
5110 :
5111 : adjustedFrame = AdjustFrameForSelectionStyles(this);
5112 0 :
5113 : // -moz-user-select: all needs special handling, because clicking on it
5114 : // should lead to the whole frame being selected
5115 : if (adjustedFrame && adjustedFrame->StyleUIReset()->mUserSelect ==
5116 0 : StyleUserSelect::All) {
5117 : nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
5118 0 : return OffsetsForSingleFrame(adjustedFrame, adjustedPoint);
5119 0 : }
5120 :
5121 : // For other cases, try to find a closest frame starting from the parent of
5122 : // the unselectable frame
5123 : if (adjustedFrame != this)
5124 0 : adjustedFrame = adjustedFrame->GetParent();
5125 0 : }
5126 :
5127 : nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
5128 0 :
5129 : FrameTarget closest =
5130 : GetSelectionClosestFrame(adjustedFrame, adjustedPoint, aFlags);
5131 0 :
5132 : // If the correct offset is at one end of a frame, use offset-based
5133 : // calculation method
5134 : if (closest.frameEdge) {
5135 0 : ContentOffsets offsets;
5136 0 : FrameContentRange range = GetRangeForFrame(closest.frame);
5137 0 : offsets.content = range.content;
5138 0 : if (closest.afterFrame)
5139 0 : offsets.offset = range.end;
5140 0 : else
5141 : offsets.offset = range.start;
5142 0 : offsets.secondaryOffset = offsets.offset;
5143 0 : offsets.associate = offsets.offset == range.start ?
5144 0 : CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
5145 : return offsets;
5146 0 : }
5147 :
5148 : nsPoint pt;
5149 0 : if (closest.frame != this) {
5150 0 : if (nsSVGUtils::IsInSVGTextSubtree(closest.frame)) {
5151 0 : pt = nsLayoutUtils::TransformAncestorPointToFrame(closest.frame,
5152 0 : aPoint, this);
5153 : } else {
5154 : pt = aPoint - closest.frame->GetOffsetTo(this);
5155 0 : }
5156 : } else {
5157 : pt = aPoint;
5158 0 : }
5159 : return static_cast<nsFrame*>(closest.frame)->CalcContentOffsetsFromFramePoint(pt);
5160 0 :
5161 : // XXX should I add some kind of offset standardization?
5162 : // consider <b>xxxxx</b><i>zzzzz</i>; should any click between the last
5163 : // x and first z put the cursor in the same logical position in addition
5164 : // to the same visual position?
5165 : }
5166 :
5167 : nsIFrame::ContentOffsets nsFrame::CalcContentOffsetsFromFramePoint(const nsPoint& aPoint)
5168 0 : {
5169 : return OffsetsForSingleFrame(this, aPoint);
5170 0 : }
5171 :
5172 : void
5173 : nsIFrame::AssociateImage(const nsStyleImage& aImage, nsPresContext* aPresContext,
5174 0 : uint32_t aImageLoaderFlags)
5175 : {
5176 : if (aImage.GetType() != eStyleImageType_Image) {
5177 2 : return;
5178 : }
5179 :
5180 : imgRequestProxy* req = aImage.GetImageData();
5181 0 : if (!req) {
5182 0 : return;
5183 : }
5184 : mozilla::css::ImageLoader* loader =
5185 : aPresContext->Document()->StyleImageLoader();
5186 0 :
5187 : // If this fails there's not much we can do ...
5188 : loader->AssociateRequestToFrame(req, this, aImageLoaderFlags);
5189 0 : }
5190 :
5191 : nsresult
5192 : nsFrame::GetCursor(const nsPoint& aPoint,
5193 0 : nsIFrame::Cursor& aCursor)
5194 : {
5195 : FillCursorInformationFromStyle(StyleUserInterface(), aCursor);
5196 0 : if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
5197 0 : // If this is editable, I-beam cursor is better for most elements.
5198 : aCursor.mCursor =
5199 0 : (mContent && mContent->IsEditable())
5200 0 : ? NS_STYLE_CURSOR_TEXT : NS_STYLE_CURSOR_DEFAULT;
5201 0 : }
5202 : if (NS_STYLE_CURSOR_TEXT == aCursor.mCursor &&
5203 0 : GetWritingMode().IsVertical()) {
5204 0 : // Per CSS UI spec, UA may treat value 'text' as
5205 : // 'vertical-text' for vertical text.
5206 : aCursor.mCursor = NS_STYLE_CURSOR_VERTICAL_TEXT;
5207 0 : }
5208 :
5209 : return NS_OK;
5210 0 : }
5211 :
5212 : // Resize and incremental reflow
5213 :
5214 : /* virtual */ void
5215 : nsFrame::MarkIntrinsicISizesDirty()
5216 110 : {
5217 : // This version is meant only for what used to be box-to-block adaptors.
5218 : // It should not be called by other derived classes.
5219 : if (::IsXULBoxWrapped(this)) {
5220 0 : nsBoxLayoutMetrics *metrics = BoxMetrics();
5221 49 :
5222 : SizeNeedsRecalc(metrics->mPrefSize);
5223 49 : SizeNeedsRecalc(metrics->mMinSize);
5224 49 : SizeNeedsRecalc(metrics->mMaxSize);
5225 49 : SizeNeedsRecalc(metrics->mBlockPrefSize);
5226 49 : SizeNeedsRecalc(metrics->mBlockMinSize);
5227 49 : CoordNeedsRecalc(metrics->mFlex);
5228 49 : CoordNeedsRecalc(metrics->mAscent);
5229 49 : }
5230 :
5231 : if (GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT) {
5232 0 : nsFontInflationData::MarkFontInflationDataTextDirty(this);
5233 52 : }
5234 : }
5235 110 :
5236 : /* virtual */ nscoord
5237 : nsFrame::GetMinISize(gfxContext *aRenderingContext)
5238 48 : {
5239 : nscoord result = 0;
5240 48 : DISPLAY_MIN_WIDTH(this, result);
5241 96 : return result;
5242 96 : }
5243 :
5244 : /* virtual */ nscoord
5245 : nsFrame::GetPrefISize(gfxContext *aRenderingContext)
5246 48 : {
5247 : nscoord result = 0;
5248 0 : DISPLAY_PREF_WIDTH(this, result);
5249 96 : return result;
5250 96 : }
5251 :
5252 : /* virtual */ void
5253 : nsFrame::AddInlineMinISize(gfxContext* aRenderingContext,
5254 3 : nsIFrame::InlineMinISizeData* aData)
5255 : {
5256 : nscoord isize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
5257 3 : this, nsLayoutUtils::MIN_ISIZE);
5258 0 : aData->DefaultAddInlineMinISize(this, isize);
5259 0 : }
5260 3 :
5261 : /* virtual */ void
5262 : nsFrame::AddInlinePrefISize(gfxContext* aRenderingContext,
5263 0 : nsIFrame::InlinePrefISizeData* aData)
5264 : {
5265 : nscoord isize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
5266 0 : this, nsLayoutUtils::PREF_ISIZE);
5267 3 : aData->DefaultAddInlinePrefISize(isize);
5268 3 : }
5269 0 :
5270 : void
5271 : nsIFrame::InlineMinISizeData::DefaultAddInlineMinISize(nsIFrame* aFrame,
5272 0 : nscoord aISize,
5273 : bool aAllowBreak)
5274 : {
5275 : auto parent = aFrame->GetParent();
5276 3 : MOZ_ASSERT(parent, "Must have a parent if we get here!");
5277 3 : const bool mayBreak = aAllowBreak &&
5278 0 : !aFrame->CanContinueTextRun() &&
5279 6 : !parent->Style()->ShouldSuppressLineBreak() &&
5280 12 : parent->StyleText()->WhiteSpaceCanWrap(parent);
5281 6 : if (mayBreak) {
5282 0 : OptionallyBreak();
5283 0 : }
5284 : mTrailingWhitespace = 0;
5285 0 : mSkipWhitespace = false;
5286 0 : mCurrentLine += aISize;
5287 0 : mAtStartOfLine = false;
5288 0 : if (mayBreak) {
5289 0 : OptionallyBreak();
5290 0 : }
5291 : }
5292 3 :
5293 : void
5294 : nsIFrame::InlinePrefISizeData::DefaultAddInlinePrefISize(nscoord aISize)
5295 0 : {
5296 : mCurrentLine = NSCoordSaturatingAdd(mCurrentLine, aISize);
5297 0 : mTrailingWhitespace = 0;
5298 3 : mSkipWhitespace = false;
5299 3 : mLineIsEmpty = false;
5300 0 : }
5301 3 :
5302 : void
5303 : nsIFrame::InlineMinISizeData::ForceBreak()
5304 0 : {
5305 : mCurrentLine -= mTrailingWhitespace;
5306 13 : mPrevLines = std::max(mPrevLines, mCurrentLine);
5307 26 : mCurrentLine = mTrailingWhitespace = 0;
5308 0 :
5309 : for (uint32_t i = 0, i_end = mFloats.Length(); i != i_end; ++i) {
5310 0 : nscoord float_min = mFloats[i].Width();
5311 0 : if (float_min > mPrevLines)
5312 0 : mPrevLines = float_min;
5313 0 : }
5314 : mFloats.Clear();
5315 13 : mSkipWhitespace = true;
5316 0 : }
5317 13 :
5318 : void
5319 : nsIFrame::InlineMinISizeData::OptionallyBreak(nscoord aHyphenWidth)
5320 0 : {
5321 : // If we can fit more content into a smaller width by staying on this
5322 : // line (because we're still at a negative offset due to negative
5323 : // text-indent or negative margin), don't break. Otherwise, do the
5324 : // same as ForceBreak. it doesn't really matter when we accumulate
5325 : // floats.
5326 : if (mCurrentLine + aHyphenWidth < 0 || mAtStartOfLine)
5327 6 : return;
5328 : mCurrentLine += aHyphenWidth;
5329 0 : ForceBreak();
5330 0 : }
5331 :
5332 : void
5333 : nsIFrame::InlinePrefISizeData::ForceBreak(StyleClear aBreakType)
5334 0 : {
5335 : MOZ_ASSERT(aBreakType == StyleClear::None ||
5336 10 : aBreakType == StyleClear::Both ||
5337 : aBreakType == StyleClear::Left ||
5338 : aBreakType == StyleClear::Right,
5339 : "Must be a physical break type");
5340 :
5341 : // If this force break is not clearing any float, we can leave all the
5342 : // floats to the next force break.
5343 : if (mFloats.Length() != 0 && aBreakType != StyleClear::None) {
5344 0 : // preferred widths accumulated for floats that have already
5345 : // been cleared past
5346 : nscoord floats_done = 0,
5347 0 : // preferred widths accumulated for floats that have not yet
5348 : // been cleared past
5349 : floats_cur_left = 0,
5350 0 : floats_cur_right = 0;
5351 0 : const WritingMode wm = mLineContainerWM;
5352 0 :
5353 : for (uint32_t i = 0, i_end = mFloats.Length(); i != i_end; ++i) {
5354 0 : const FloatInfo& floatInfo = mFloats[i];
5355 0 : const nsStyleDisplay* floatDisp = floatInfo.Frame()->StyleDisplay();
5356 0 : StyleClear breakType = floatDisp->PhysicalBreakType(wm);
5357 0 : if (breakType == StyleClear::Left ||
5358 0 : breakType == StyleClear::Right ||
5359 0 : breakType == StyleClear::Both) {
5360 0 : nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left,
5361 0 : floats_cur_right);
5362 0 : if (floats_cur > floats_done) {
5363 0 : floats_done = floats_cur;
5364 0 : }
5365 : if (breakType != StyleClear::Right) {
5366 0 : floats_cur_left = 0;
5367 0 : }
5368 : if (breakType != StyleClear::Left) {
5369 0 : floats_cur_right = 0;
5370 0 : }
5371 : }
5372 :
5373 : StyleFloat floatStyle = floatDisp->PhysicalFloats(wm);
5374 0 : nscoord& floats_cur =
5375 : floatStyle == StyleFloat::Left ? floats_cur_left : floats_cur_right;
5376 0 : nscoord floatWidth = floatInfo.Width();
5377 0 : // Negative-width floats don't change the available space so they
5378 : // shouldn't change our intrinsic line width either.
5379 : floats_cur =
5380 0 : NSCoordSaturatingAdd(floats_cur, std::max(0, floatWidth));
5381 0 : }
5382 :
5383 : nscoord floats_cur =
5384 : NSCoordSaturatingAdd(floats_cur_left, floats_cur_right);
5385 0 : if (floats_cur > floats_done)
5386 0 : floats_done = floats_cur;
5387 0 :
5388 : mCurrentLine = NSCoordSaturatingAdd(mCurrentLine, floats_done);
5389 0 :
5390 : if (aBreakType == StyleClear::Both) {
5391 0 : mFloats.Clear();
5392 0 : } else {
5393 : // If the break type does not clear all floats, it means there may
5394 : // be some floats whose isize should contribute to the intrinsic
5395 : // isize of the next line. The code here scans the current mFloats
5396 : // and keeps floats which are not cleared by this break. Note that
5397 : // floats may be cleared directly or indirectly. See below.
5398 : nsTArray<FloatInfo> newFloats;
5399 0 : MOZ_ASSERT(aBreakType == StyleClear::Left ||
5400 0 : aBreakType == StyleClear::Right,
5401 : "Other values should have been handled in other branches");
5402 : StyleFloat clearFloatType =
5403 : aBreakType == StyleClear::Left ? StyleFloat::Left : StyleFloat::Right;
5404 0 : // Iterate the array in reverse so that we can stop when there are
5405 : // no longer any floats we need to keep. See below.
5406 : for (FloatInfo& floatInfo : Reversed(mFloats)) {
5407 0 : const nsStyleDisplay* floatDisp = floatInfo.Frame()->StyleDisplay();
5408 0 : if (floatDisp->PhysicalFloats(wm) != clearFloatType) {
5409 0 : newFloats.AppendElement(floatInfo);
5410 0 : } else {
5411 : // This is a float on the side that this break directly clears
5412 : // which means we're not keeping it in mFloats. However, if
5413 : // this float clears floats on the opposite side (via a value
5414 : // of either 'both' or one of 'left'/'right'), any remaining
5415 : // (earlier) floats on that side would be indirectly cleared
5416 : // as well. Thus, we should break out of this loop and stop
5417 : // considering earlier floats to be kept in mFloats.
5418 : StyleClear floatBreakType = floatDisp->PhysicalBreakType(wm);
5419 0 : if (floatBreakType != aBreakType &&
5420 0 : floatBreakType != StyleClear::None) {
5421 0 : break;
5422 : }
5423 : }
5424 : }
5425 : newFloats.Reverse();
5426 0 : mFloats = std::move(newFloats);
5427 0 : }
5428 : }
5429 :
5430 : mCurrentLine =
5431 0 : NSCoordSaturatingSubtract(mCurrentLine, mTrailingWhitespace, nscoord_MAX);
5432 0 : mPrevLines = std::max(mPrevLines, mCurrentLine);
5433 20 : mCurrentLine = mTrailingWhitespace = 0;
5434 10 : mSkipWhitespace = true;
5435 10 : mLineIsEmpty = true;
5436 0 : }
5437 10 :
5438 : static nscoord
5439 : ResolveMargin(const nsStyleCoord& aStyle, nscoord aPercentageBasis)
5440 12 : {
5441 : if (aStyle.GetUnit() == eStyleUnit_Auto) {
5442 0 : return nscoord(0);
5443 : }
5444 : return nsLayoutUtils::ResolveToLength<false>(aStyle, aPercentageBasis);
5445 12 : }
5446 :
5447 : static nscoord
5448 : ResolvePadding(const nsStyleCoord& aStyle, nscoord aPercentageBasis)
5449 : {
5450 : return nsLayoutUtils::ResolveToLength<true>(aStyle, aPercentageBasis);
5451 0 : }
5452 :
5453 : static nsIFrame::IntrinsicISizeOffsetData
5454 : IntrinsicSizeOffsets(nsIFrame* aFrame, nscoord aPercentageBasis, bool aForISize)
5455 6 : {
5456 : nsIFrame::IntrinsicISizeOffsetData result;
5457 6 : WritingMode wm = aFrame->GetWritingMode();
5458 6 : const auto& margin = aFrame->StyleMargin()->mMargin;
5459 6 : bool verticalAxis = aForISize == wm.IsVertical();
5460 6 : if (verticalAxis) {
5461 0 : result.hMargin += ResolveMargin(margin.GetTop(), aPercentageBasis);
5462 0 : result.hMargin += ResolveMargin(margin.GetBottom(), aPercentageBasis);
5463 0 : } else {
5464 : result.hMargin += ResolveMargin(margin.GetLeft(), aPercentageBasis);
5465 12 : result.hMargin += ResolveMargin(margin.GetRight(), aPercentageBasis);
5466 0 : }
5467 :
5468 : const auto& padding = aFrame->StylePadding()->mPadding;
5469 0 : if (verticalAxis) {
5470 0 : result.hPadding += ResolvePadding(padding.GetTop(), aPercentageBasis);
5471 0 : result.hPadding += ResolvePadding(padding.GetBottom(), aPercentageBasis);
5472 0 : } else {
5473 : result.hPadding += ResolvePadding(padding.GetLeft(), aPercentageBasis);
5474 18 : result.hPadding += ResolvePadding(padding.GetRight(), aPercentageBasis);
5475 18 : }
5476 :
5477 : const nsStyleBorder* styleBorder = aFrame->StyleBorder();
5478 6 : if (verticalAxis) {
5479 6 : result.hBorder += styleBorder->GetComputedBorderWidth(eSideTop);
5480 0 : result.hBorder += styleBorder->GetComputedBorderWidth(eSideBottom);
5481 0 : } else {
5482 : result.hBorder += styleBorder->GetComputedBorderWidth(eSideLeft);
5483 0 : result.hBorder += styleBorder->GetComputedBorderWidth(eSideRight);
5484 6 : }
5485 :
5486 : const nsStyleDisplay* disp = aFrame->StyleDisplay();
5487 6 : if (aFrame->IsThemed(disp)) {
5488 0 : nsPresContext* presContext = aFrame->PresContext();
5489 0 :
5490 : LayoutDeviceIntMargin border =
5491 : presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
5492 0 : aFrame, disp->mAppearance);
5493 0 : result.hBorder =
5494 0 : presContext->DevPixelsToAppUnits(verticalAxis ? border.TopBottom()
5495 0 : : border.LeftRight());
5496 :
5497 : LayoutDeviceIntMargin padding;
5498 0 : if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
5499 0 : aFrame, disp->mAppearance,
5500 0 : &padding)) {
5501 0 : result.hPadding =
5502 0 : presContext->DevPixelsToAppUnits(verticalAxis ? padding.TopBottom()
5503 0 : : padding.LeftRight());
5504 : }
5505 : }
5506 : return result;
5507 0 : }
5508 :
5509 : /* virtual */ nsIFrame::IntrinsicISizeOffsetData
5510 : nsFrame::IntrinsicISizeOffsets(nscoord aPercentageBasis)
5511 6 : {
5512 : return IntrinsicSizeOffsets(this, aPercentageBasis, true);
5513 0 : }
5514 :
5515 : nsIFrame::IntrinsicISizeOffsetData
5516 : nsIFrame::IntrinsicBSizeOffsets(nscoord aPercentageBasis)
5517 0 : {
5518 : return IntrinsicSizeOffsets(this, aPercentageBasis, false);
5519 0 : }
5520 :
5521 : /* virtual */ IntrinsicSize
5522 : nsFrame::GetIntrinsicSize()
5523 0 : {
5524 : return IntrinsicSize(); // default is width/height set to eStyleUnit_None
5525 0 : }
5526 :
5527 : /* virtual */ nsSize
5528 : nsFrame::GetIntrinsicRatio()
5529 183 : {
5530 : return nsSize(0, 0);
5531 0 : }
5532 :
5533 : /* virtual */
5534 : LogicalSize
5535 : nsFrame::ComputeSize(gfxContext* aRenderingContext,
5536 0 : WritingMode aWM,
5537 : const LogicalSize& aCBSize,
5538 : nscoord aAvailableISize,
5539 : const LogicalSize& aMargin,
5540 : const LogicalSize& aBorder,
5541 : const LogicalSize& aPadding,
5542 : ComputeSizeFlags aFlags)
5543 : {
5544 : MOZ_ASSERT(GetIntrinsicRatio() == nsSize(0,0),
5545 0 : "Please override this method and call "
5546 : "nsFrame::ComputeSizeWithIntrinsicDimensions instead.");
5547 : LogicalSize result = ComputeAutoSize(aRenderingContext, aWM,
5548 : aCBSize, aAvailableISize,
5549 : aMargin, aBorder, aPadding,
5550 : aFlags);
5551 0 : const nsStylePosition *stylePos = StylePosition();
5552 170 :
5553 : LogicalSize boxSizingAdjust(aWM);
5554 0 : if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
5555 0 : boxSizingAdjust = aBorder + aPadding;
5556 0 : }
5557 : nscoord boxSizingToMarginEdgeISize =
5558 : aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) -
5559 170 : boxSizingAdjust.ISize(aWM);
5560 0 :
5561 : const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM);
5562 0 : const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM);
5563 0 :
5564 : auto parentFrame = GetParent();
5565 0 : auto alignCB = parentFrame;
5566 170 : bool isGridItem = parentFrame && parentFrame->IsGridContainerFrame() &&
5567 170 : !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
5568 170 : if (parentFrame && parentFrame->IsTableWrapperFrame() && IsTableFrame()) {
5569 0 : // An inner table frame is sized as a grid item if its table wrapper is,
5570 : // because they actually have the same CB (the wrapper's CB).
5571 : // @see ReflowInput::InitCBReflowInput
5572 : auto tableWrapper = GetParent();
5573 0 : auto grandParent = tableWrapper->GetParent();
5574 0 : isGridItem = (grandParent->IsGridContainerFrame() &&
5575 0 : !(tableWrapper->GetStateBits() & NS_FRAME_OUT_OF_FLOW));
5576 0 : if (isGridItem) {
5577 0 : // When resolving justify/align-self below, we want to use the grid
5578 : // container's justify/align-items value and WritingMode.
5579 : alignCB = grandParent;
5580 0 : }
5581 : }
5582 : bool isFlexItem = parentFrame && parentFrame->IsFlexContainerFrame() &&
5583 170 : !parentFrame->HasAnyStateBits(NS_STATE_FLEX_IS_EMULATING_LEGACY_BOX) &&
5584 170 : !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
5585 0 : // This variable only gets set (and used) if isFlexItem is true. It
5586 : // indicates which axis (in this frame's own WM) corresponds to its
5587 : // flex container's main axis.
5588 : LogicalAxis flexMainAxis = eLogicalAxisInline; // (init to make valgrind happy)
5589 170 : if (isFlexItem) {
5590 170 : // Flex items use their "flex-basis" property in place of their main-size
5591 : // property for sizing purposes, *unless* they have "flex-basis:auto", in
5592 : // which case they use their main-size property after all.
5593 : flexMainAxis = nsFlexContainerFrame::IsItemInlineAxisMainAxis(this) ?
5594 0 : eLogicalAxisInline : eLogicalAxisBlock;
5595 :
5596 : // NOTE: The logic here should match the similar chunk for updating
5597 : // mainAxisCoord in nsFrame::ComputeSizeWithIntrinsicDimensions() (aside
5598 : // from using a different dummy value in the IsUsedFlexBasisContent() case).
5599 : const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
5600 0 : auto& mainAxisCoord = (flexMainAxis == eLogicalAxisInline
5601 : ? inlineStyleCoord : blockStyleCoord);
5602 0 :
5603 : // NOTE: If we're a table-wrapper frame, we skip this clause and just stick
5604 : // with 'main-size:auto' behavior (which -- unlike 'content'
5605 : // i.e. 'max-content' -- will give us the ability to honor percent sizes on
5606 : // our table-box child when resolving the flex base size). The flexbox spec
5607 : // doesn't call for this special case, but webcompat & regression-avoidance
5608 : // seems to require it, for the time being... Tables sure are special.
5609 : if (nsFlexContainerFrame::IsUsedFlexBasisContent(flexBasis,
5610 0 : mainAxisCoord) &&
5611 0 : MOZ_LIKELY(!IsTableWrapperFrame())) {
5612 0 : static const nsStyleCoord maxContStyleCoord(NS_STYLE_WIDTH_MAX_CONTENT,
5613 : eStyleUnit_Enumerated);
5614 0 : mainAxisCoord = &maxContStyleCoord;
5615 0 : // (Note: if our main axis is the block axis, then this 'max-content'
5616 : // value will be treated like 'auto', via the IsAutoBSize() call below.)
5617 : } else if (flexBasis->GetUnit() != eStyleUnit_Auto) {
5618 0 : // For all other non-'auto' flex-basis values, we just swap in the
5619 : // flex-basis itself for the main-size property.
5620 : mainAxisCoord = flexBasis;
5621 0 : } // else: flex-basis is 'auto', which is deferring to some explicit value
5622 : // in mainAxisCoord. So we proceed w/o touching mainAxisCoord.
5623 : }
5624 :
5625 : // Compute inline-axis size
5626 : if (inlineStyleCoord->GetUnit() != eStyleUnit_Auto) {
5627 0 : result.ISize(aWM) =
5628 0 : ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
5629 0 : boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
5630 0 : *inlineStyleCoord, aFlags);
5631 : } else if (MOZ_UNLIKELY(isGridItem) &&
5632 328 : !IS_TRUE_OVERFLOW_CONTAINER(this)) {
5633 0 : // 'auto' inline-size for grid-level box - fill the CB for 'stretch' /
5634 : // 'normal' and clamp it to the CB if requested:
5635 : bool stretch = false;
5636 0 : if (!(aFlags & nsIFrame::eShrinkWrap) &&
5637 0 : !StyleMargin()->HasInlineAxisAuto(aWM)) {
5638 0 : auto inlineAxisAlignment =
5639 : aWM.IsOrthogonalTo(alignCB->GetWritingMode()) ?
5640 0 : StylePosition()->UsedAlignSelf(alignCB->Style()) :
5641 0 : StylePosition()->UsedJustifySelf(alignCB->Style());
5642 0 : stretch = inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
5643 0 : inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH;
5644 0 : }
5645 : if (stretch || (aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
5646 0 : auto iSizeToFillCB = std::max(nscoord(0), aCBSize.ISize(aWM) -
5647 0 : aPadding.ISize(aWM) -
5648 0 : aBorder.ISize(aWM) -
5649 0 : aMargin.ISize(aWM));
5650 0 : if (stretch || result.ISize(aWM) > iSizeToFillCB) {
5651 0 : result.ISize(aWM) = iSizeToFillCB;
5652 0 : }
5653 : }
5654 : }
5655 :
5656 : // Flex items ignore their min & max sizing properties in their
5657 : // flex container's main-axis. (Those properties get applied later in
5658 : // the flexbox algorithm.)
5659 : const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM);
5660 170 : nscoord maxISize = NS_UNCONSTRAINEDSIZE;
5661 170 : if (maxISizeCoord.GetUnit() != eStyleUnit_None &&
5662 0 : !(isFlexItem && flexMainAxis == eLogicalAxisInline)) {
5663 8 : maxISize =
5664 0 : ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
5665 8 : boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
5666 8 : maxISizeCoord, aFlags);
5667 : result.ISize(aWM) = std::min(maxISize, result.ISize(aWM));
5668 16 : }
5669 :
5670 : const nsStyleCoord& minISizeCoord = stylePos->MinISize(aWM);
5671 170 : nscoord minISize;
5672 : if (minISizeCoord.GetUnit() != eStyleUnit_Auto &&
5673 0 : !(isFlexItem && flexMainAxis == eLogicalAxisInline)) {
5674 0 : minISize =
5675 1 : ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
5676 0 : boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
5677 0 : minISizeCoord, aFlags);
5678 : } else if (MOZ_UNLIKELY(aFlags & eIApplyAutoMinSize)) {
5679 169 : // This implements "Implied Minimum Size of Grid Items".
5680 : // https://drafts.csswg.org/css-grid/#min-size-auto
5681 : minISize = std::min(maxISize, GetMinISize(aRenderingContext));
5682 0 : if (inlineStyleCoord->IsCoordPercentCalcUnit()) {
5683 0 : minISize = std::min(minISize, result.ISize(aWM));
5684 0 : } else if (aFlags & eIClampMarginBoxMinSize) {
5685 0 : // "if the grid item spans only grid tracks that have a fixed max track
5686 : // sizing function, its automatic minimum size in that dimension is
5687 : // further clamped to less than or equal to the size necessary to fit
5688 : // its margin box within the resulting grid area (flooring at zero)"
5689 : // https://drafts.csswg.org/css-grid/#min-size-auto
5690 : auto maxMinISize = std::max(nscoord(0), aCBSize.ISize(aWM) -
5691 0 : aPadding.ISize(aWM) -
5692 0 : aBorder.ISize(aWM) -
5693 0 : aMargin.ISize(aWM));
5694 0 : minISize = std::min(minISize, maxMinISize);
5695 0 : }
5696 : } else {
5697 : // Treat "min-width: auto" as 0.
5698 : // NOTE: Technically, "auto" is supposed to behave like "min-content" on
5699 : // flex items. However, we don't need to worry about that here, because
5700 : // flex items' min-sizes are intentionally ignored until the flex
5701 : // container explicitly considers them during space distribution.
5702 : minISize = 0;
5703 0 : }
5704 : result.ISize(aWM) = std::max(minISize, result.ISize(aWM));
5705 0 :
5706 : // Compute block-axis size
5707 : // (but not if we have auto bsize or if we received the "eUseAutoBSize"
5708 : // flag -- then, we'll just stick with the bsize that we already calculated
5709 : // in the initial ComputeAutoSize() call.)
5710 : if (!(aFlags & nsIFrame::eUseAutoBSize)) {
5711 0 : if (!nsLayoutUtils::IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM))) {
5712 0 : result.BSize(aWM) =
5713 0 : nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
5714 0 : boxSizingAdjust.BSize(aWM),
5715 10 : *blockStyleCoord);
5716 : } else if (MOZ_UNLIKELY(isGridItem) &&
5717 320 : blockStyleCoord->GetUnit() == eStyleUnit_Auto &&
5718 160 : !IS_TRUE_OVERFLOW_CONTAINER(this)) {
5719 0 : auto cbSize = aCBSize.BSize(aWM);
5720 0 : if (cbSize != NS_AUTOHEIGHT) {
5721 0 : // 'auto' block-size for grid-level box - fill the CB for 'stretch' /
5722 : // 'normal' and clamp it to the CB if requested:
5723 : bool stretch = false;
5724 0 : if (!StyleMargin()->HasBlockAxisAuto(aWM)) {
5725 0 : auto blockAxisAlignment =
5726 : !aWM.IsOrthogonalTo(alignCB->GetWritingMode()) ?
5727 0 : StylePosition()->UsedAlignSelf(alignCB->Style()) :
5728 0 : StylePosition()->UsedJustifySelf(alignCB->Style());
5729 0 : stretch = blockAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
5730 0 : blockAxisAlignment == NS_STYLE_ALIGN_STRETCH;
5731 0 : }
5732 : if (stretch || (aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize)) {
5733 0 : auto bSizeToFillCB = std::max(nscoord(0), cbSize -
5734 0 : aPadding.BSize(aWM) -
5735 0 : aBorder.BSize(aWM) -
5736 0 : aMargin.BSize(aWM));
5737 0 : if (stretch || (result.BSize(aWM) != NS_AUTOHEIGHT &&
5738 0 : result.BSize(aWM) > bSizeToFillCB)) {
5739 0 : result.BSize(aWM) = bSizeToFillCB;
5740 0 : }
5741 : }
5742 : }
5743 : }
5744 : }
5745 :
5746 : const nsStyleCoord& maxBSizeCoord = stylePos->MaxBSize(aWM);
5747 0 :
5748 : if (result.BSize(aWM) != NS_UNCONSTRAINEDSIZE) {
5749 170 : if (!nsLayoutUtils::IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) &&
5750 14 : !(isFlexItem && flexMainAxis == eLogicalAxisBlock)) {
5751 0 : nscoord maxBSize =
5752 : nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
5753 0 : boxSizingAdjust.BSize(aWM),
5754 0 : maxBSizeCoord);
5755 0 : result.BSize(aWM) = std::min(maxBSize, result.BSize(aWM));
5756 0 : }
5757 :
5758 : const nsStyleCoord& minBSizeCoord = stylePos->MinBSize(aWM);
5759 14 :
5760 : if (!nsLayoutUtils::IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) &&
5761 15 : !(isFlexItem && flexMainAxis == eLogicalAxisBlock)) {
5762 1 : nscoord minBSize =
5763 : nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
5764 1 : boxSizingAdjust.BSize(aWM),
5765 0 : minBSizeCoord);
5766 1 : result.BSize(aWM) = std::max(minBSize, result.BSize(aWM));
5767 0 : }
5768 : }
5769 :
5770 : const nsStyleDisplay *disp = StyleDisplay();
5771 170 : if (IsThemed(disp)) {
5772 170 : LayoutDeviceIntSize widget;
5773 0 : bool canOverride = true;
5774 0 : nsPresContext *presContext = PresContext();
5775 0 : presContext->GetTheme()->
5776 0 : GetMinimumWidgetSize(presContext, this, disp->mAppearance,
5777 0 : &widget, &canOverride);
5778 0 :
5779 : // Convert themed widget's physical dimensions to logical coords
5780 : LogicalSize size(aWM,
5781 : nsSize(presContext->DevPixelsToAppUnits(widget.width),
5782 0 : presContext->DevPixelsToAppUnits(widget.height)));
5783 0 :
5784 : // GMWS() returns border-box; we need content-box
5785 : size.ISize(aWM) -= aBorder.ISize(aWM) + aPadding.ISize(aWM);
5786 0 : size.BSize(aWM) -= aBorder.BSize(aWM) + aPadding.BSize(aWM);
5787 0 :
5788 : if (size.BSize(aWM) > result.BSize(aWM) || !canOverride) {
5789 0 : result.BSize(aWM) = size.BSize(aWM);
5790 0 : }
5791 : if (size.ISize(aWM) > result.ISize(aWM) || !canOverride) {
5792 0 : result.ISize(aWM) = size.ISize(aWM);
5793 0 : }
5794 : }
5795 :
5796 : result.ISize(aWM) = std::max(0, result.ISize(aWM));
5797 0 : result.BSize(aWM) = std::max(0, result.BSize(aWM));
5798 0 :
5799 : return result;
5800 0 : }
5801 :
5802 : LogicalSize
5803 : nsFrame::ComputeSizeWithIntrinsicDimensions(gfxContext* aRenderingContext,
5804 0 : WritingMode aWM,
5805 : const IntrinsicSize& aIntrinsicSize,
5806 : nsSize aIntrinsicRatio,
5807 : const LogicalSize& aCBSize,
5808 : const LogicalSize& aMargin,
5809 : const LogicalSize& aBorder,
5810 : const LogicalSize& aPadding,
5811 : ComputeSizeFlags aFlags)
5812 : {
5813 : const nsStylePosition* stylePos = StylePosition();
5814 0 : const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM);
5815 0 : const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM);
5816 0 : auto* parentFrame = GetParent();
5817 0 : const bool isGridItem = parentFrame && parentFrame->IsGridContainerFrame() &&
5818 0 : !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
5819 0 : const bool isFlexItem = parentFrame && parentFrame->IsFlexContainerFrame() &&
5820 0 : !parentFrame->HasAnyStateBits(NS_STATE_FLEX_IS_EMULATING_LEGACY_BOX) &&
5821 0 : !HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
5822 0 : // This variable only gets set (and used) if isFlexItem is true. It
5823 : // indicates which axis (in this frame's own WM) corresponds to its
5824 : // flex container's main axis.
5825 : LogicalAxis flexMainAxis = eLogicalAxisInline; // (init to make valgrind happy)
5826 0 : Maybe<nsStyleCoord> imposedMainSizeStyleCoord;
5827 0 :
5828 : // If this is a flex item, and we're measuring its cross size after flexing
5829 : // to resolve its main size, then we need to use the resolved main size
5830 : // that the container provides to us *instead of* the main-size coordinate
5831 : // from our style struct. (Otherwise, we'll be using an irrelevant value in
5832 : // the aspect-ratio calculations below.)
5833 : if (isFlexItem) {
5834 0 : flexMainAxis = nsFlexContainerFrame::IsItemInlineAxisMainAxis(this) ?
5835 0 : eLogicalAxisInline : eLogicalAxisBlock;
5836 :
5837 : // If FlexItemMainSizeOverride frame-property is set, then that means the
5838 : // flex container is imposing a main-size on this flex item for it to use
5839 : // as its size in the container's main axis.
5840 : bool didImposeMainSize;
5841 : nscoord imposedMainSize =
5842 : GetProperty(nsIFrame::FlexItemMainSizeOverride(), &didImposeMainSize);
5843 0 : if (didImposeMainSize) {
5844 0 : imposedMainSizeStyleCoord.emplace(imposedMainSize,
5845 : nsStyleCoord::CoordConstructor);
5846 0 : if (flexMainAxis == eLogicalAxisInline) {
5847 0 : inlineStyleCoord = imposedMainSizeStyleCoord.ptr();
5848 0 : } else {
5849 : blockStyleCoord = imposedMainSizeStyleCoord.ptr();
5850 0 : }
5851 :
5852 : } else {
5853 : // Flex items use their "flex-basis" property in place of their main-size
5854 : // property (e.g. "width") for sizing purposes, *unless* they have
5855 : // "flex-basis:auto", in which case they use their main-size property
5856 : // after all.
5857 : // NOTE: The logic here should match the similar chunk for updating
5858 : // mainAxisCoord in nsFrame::ComputeSize() (aside from using a different
5859 : // dummy value in the IsUsedFlexBasisContent() case).
5860 : const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
5861 0 : auto& mainAxisCoord = (flexMainAxis == eLogicalAxisInline
5862 : ? inlineStyleCoord : blockStyleCoord);
5863 0 :
5864 : if (nsFlexContainerFrame::IsUsedFlexBasisContent(flexBasis,
5865 0 : mainAxisCoord)) {
5866 : // If we get here, we're resolving the flex base size for a flex item,
5867 : // and we fall into the flexbox spec section 9.2 step 3, substep C (if
5868 : // we have a definite cross size) or E (if not). And specifically:
5869 : //
5870 : // * If we have a definite cross size, we're supposed to resolve our
5871 : // main-size based on that and our intrinsic ratio.
5872 : // * Otherwise, we're supposed to produce our max-content size.
5873 : //
5874 : // Conveniently, we can handle both of those scenarios (regardless of
5875 : // which substep we fall into) by using the 'auto' keyword for our
5876 : // main-axis coordinate here. (This makes sense, because the spec is
5877 : // effectively trying to produce the 'auto' sizing behavior).
5878 : static const nsStyleCoord autoStyleCoord(eStyleUnit_Auto);
5879 0 : mainAxisCoord = &autoStyleCoord;
5880 0 : } else if (flexBasis->GetUnit() != eStyleUnit_Auto) {
5881 0 : // For all other non-'auto' flex-basis values, we just swap in the
5882 : // flex-basis itself for the main-size property.
5883 : mainAxisCoord = flexBasis;
5884 0 : } // else: flex-basis is 'auto', which is deferring to some explicit
5885 : // value in mainAxisCoord. So we proceed w/o touching mainAxisCoord.
5886 : }
5887 : }
5888 :
5889 : // Handle intrinsic sizes and their interaction with
5890 : // {min-,max-,}{width,height} according to the rules in
5891 : // http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
5892 :
5893 : // Note: throughout the following section of the function, I avoid
5894 : // a * (b / c) because of its reduced accuracy relative to a * b / c
5895 : // or (a * b) / c (which are equivalent).
5896 :
5897 : const bool isAutoISize = inlineStyleCoord->GetUnit() == eStyleUnit_Auto;
5898 0 : const bool isAutoBSize =
5899 : nsLayoutUtils::IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM));
5900 0 :
5901 : LogicalSize boxSizingAdjust(aWM);
5902 0 : if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
5903 0 : boxSizingAdjust = aBorder + aPadding;
5904 0 : }
5905 : nscoord boxSizingToMarginEdgeISize =
5906 : aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) -
5907 0 : boxSizingAdjust.ISize(aWM);
5908 0 :
5909 : nscoord iSize, minISize, maxISize, bSize, minBSize, maxBSize;
5910 : enum class Stretch {
5911 : // stretch to fill the CB (preserving intrinsic ratio) in the relevant axis
5912 : eStretchPreservingRatio, // XXX not used yet
5913 : // stretch to fill the CB in the relevant axis
5914 : eStretch,
5915 : // no stretching in the relevant axis
5916 : eNoStretch,
5917 : };
5918 : // just to avoid having to type these out everywhere:
5919 : const auto eStretchPreservingRatio = Stretch::eStretchPreservingRatio;
5920 0 : const auto eStretch = Stretch::eStretch;
5921 0 : const auto eNoStretch = Stretch::eNoStretch;
5922 0 :
5923 : Stretch stretchI = eNoStretch; // stretch behavior in the inline axis
5924 0 : Stretch stretchB = eNoStretch; // stretch behavior in the block axis
5925 0 :
5926 : const bool isVertical = aWM.IsVertical();
5927 0 : const nsStyleCoord& isizeCoord =
5928 : isVertical ? aIntrinsicSize.height : aIntrinsicSize.width;
5929 0 : const bool hasIntrinsicISize = isizeCoord.GetUnit() == eStyleUnit_Coord;
5930 0 : nscoord intrinsicISize;
5931 : if (hasIntrinsicISize) {
5932 0 : intrinsicISize = std::max(nscoord(0), isizeCoord.GetCoordValue());
5933 0 : } else {
5934 : NS_ASSERTION(isizeCoord.GetUnit() == eStyleUnit_None,
5935 0 : "unexpected unit");
5936 : intrinsicISize = 0;
5937 : }
5938 :
5939 : const nsStyleCoord& bsizeCoord =
5940 : isVertical ? aIntrinsicSize.width : aIntrinsicSize.height;
5941 0 : const bool hasIntrinsicBSize = bsizeCoord.GetUnit() == eStyleUnit_Coord;
5942 0 : nscoord intrinsicBSize;
5943 : if (hasIntrinsicBSize) {
5944 0 : intrinsicBSize = std::max(nscoord(0), bsizeCoord.GetCoordValue());
5945 0 : } else {
5946 : NS_ASSERTION(bsizeCoord.GetUnit() == eStyleUnit_None,
5947 0 : "unexpected unit");
5948 : intrinsicBSize = 0;
5949 : }
5950 :
5951 : NS_ASSERTION(aIntrinsicRatio.width >= 0 && aIntrinsicRatio.height >= 0,
5952 0 : "Intrinsic ratio has a negative component!");
5953 : LogicalSize logicalRatio(aWM, aIntrinsicRatio);
5954 0 :
5955 : if (!isAutoISize) {
5956 0 : iSize = ComputeISizeValue(aRenderingContext,
5957 0 : aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
5958 0 : boxSizingToMarginEdgeISize, *inlineStyleCoord, aFlags);
5959 0 : } else if (MOZ_UNLIKELY(isGridItem)) {
5960 0 : MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(this));
5961 0 : // 'auto' inline-size for grid-level box - apply 'stretch' as needed:
5962 : auto cbSize = aCBSize.ISize(aWM);
5963 0 : if (cbSize != NS_UNCONSTRAINEDSIZE) {
5964 0 : if (!StyleMargin()->HasInlineAxisAuto(aWM)) {
5965 0 : auto inlineAxisAlignment =
5966 : aWM.IsOrthogonalTo(GetParent()->GetWritingMode()) ?
5967 0 : stylePos->UsedAlignSelf(GetParent()->Style()) :
5968 0 : stylePos->UsedJustifySelf(GetParent()->Style());
5969 0 : // Note: 'normal' means 'start' for elements with an intrinsic size
5970 : // or ratio in the relevant dimension, otherwise 'stretch'.
5971 : // https://drafts.csswg.org/css-grid/#grid-item-sizing
5972 : if ((inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL &&
5973 0 : !hasIntrinsicISize &&
5974 0 : !(logicalRatio.ISize(aWM) > 0)) ||
5975 0 : inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH) {
5976 : stretchI = eStretch;
5977 0 : }
5978 : }
5979 : if (stretchI != eNoStretch ||
5980 0 : (aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
5981 0 : iSize = std::max(nscoord(0), cbSize -
5982 0 : aPadding.ISize(aWM) -
5983 0 : aBorder.ISize(aWM) -
5984 0 : aMargin.ISize(aWM));
5985 0 : }
5986 : } else {
5987 : // Reset this flag to avoid applying the clamping below.
5988 : aFlags = ComputeSizeFlags(aFlags &
5989 0 : ~ComputeSizeFlags::eIClampMarginBoxMinSize);
5990 : }
5991 : }
5992 :
5993 : const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM);
5994 0 :
5995 : if (maxISizeCoord.GetUnit() != eStyleUnit_None &&
5996 0 : !(isFlexItem && flexMainAxis == eLogicalAxisInline)) {
5997 0 : maxISize = ComputeISizeValue(aRenderingContext,
5998 0 : aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
5999 0 : boxSizingToMarginEdgeISize, maxISizeCoord, aFlags);
6000 0 : } else {
6001 : maxISize = nscoord_MAX;
6002 : }
6003 :
6004 : // NOTE: Flex items ignore their min & max sizing properties in their
6005 : // flex container's main-axis. (Those properties get applied later in
6006 : // the flexbox algorithm.)
6007 :
6008 : const nsStyleCoord& minISizeCoord = stylePos->MinISize(aWM);
6009 0 :
6010 : if (minISizeCoord.GetUnit() != eStyleUnit_Auto &&
6011 0 : !(isFlexItem && flexMainAxis == eLogicalAxisInline)) {
6012 0 : minISize = ComputeISizeValue(aRenderingContext,
6013 0 : aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
6014 0 : boxSizingToMarginEdgeISize, minISizeCoord, aFlags);
6015 0 : } else {
6016 : // Treat "min-width: auto" as 0.
6017 : // NOTE: Technically, "auto" is supposed to behave like "min-content" on
6018 : // flex items. However, we don't need to worry about that here, because
6019 : // flex items' min-sizes are intentionally ignored until the flex
6020 : // container explicitly considers them during space distribution.
6021 : minISize = 0;
6022 : }
6023 :
6024 : if (!isAutoBSize) {
6025 0 : bSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
6026 0 : boxSizingAdjust.BSize(aWM),
6027 0 : *blockStyleCoord);
6028 0 : } else if (MOZ_UNLIKELY(isGridItem)) {
6029 0 : MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(this));
6030 0 : // 'auto' block-size for grid-level box - apply 'stretch' as needed:
6031 : auto cbSize = aCBSize.BSize(aWM);
6032 0 : if (cbSize != NS_AUTOHEIGHT) {
6033 0 : if (!StyleMargin()->HasBlockAxisAuto(aWM)) {
6034 0 : auto blockAxisAlignment =
6035 : !aWM.IsOrthogonalTo(GetParent()->GetWritingMode()) ?
6036 0 : stylePos->UsedAlignSelf(GetParent()->Style()) :
6037 0 : stylePos->UsedJustifySelf(GetParent()->Style());
6038 0 : // Note: 'normal' means 'start' for elements with an intrinsic size
6039 : // or ratio in the relevant dimension, otherwise 'stretch'.
6040 : // https://drafts.csswg.org/css-grid/#grid-item-sizing
6041 : if ((blockAxisAlignment == NS_STYLE_ALIGN_NORMAL &&
6042 0 : !hasIntrinsicBSize &&
6043 0 : !(logicalRatio.BSize(aWM) > 0)) ||
6044 0 : blockAxisAlignment == NS_STYLE_ALIGN_STRETCH) {
6045 : stretchB = eStretch;
6046 0 : }
6047 : }
6048 : if (stretchB != eNoStretch ||
6049 0 : (aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize)) {
6050 0 : bSize = std::max(nscoord(0), cbSize -
6051 0 : aPadding.BSize(aWM) -
6052 0 : aBorder.BSize(aWM) -
6053 0 : aMargin.BSize(aWM));
6054 0 : }
6055 : } else {
6056 : // Reset this flag to avoid applying the clamping below.
6057 : aFlags = ComputeSizeFlags(aFlags &
6058 0 : ~ComputeSizeFlags::eBClampMarginBoxMinSize);
6059 : }
6060 : }
6061 :
6062 : const nsStyleCoord& maxBSizeCoord = stylePos->MaxBSize(aWM);
6063 0 :
6064 : if (!nsLayoutUtils::IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) &&
6065 0 : !(isFlexItem && flexMainAxis == eLogicalAxisBlock)) {
6066 0 : maxBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
6067 0 : boxSizingAdjust.BSize(aWM), maxBSizeCoord);
6068 0 : } else {
6069 : maxBSize = nscoord_MAX;
6070 : }
6071 :
6072 : const nsStyleCoord& minBSizeCoord = stylePos->MinBSize(aWM);
6073 0 :
6074 : if (!nsLayoutUtils::IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) &&
6075 0 : !(isFlexItem && flexMainAxis == eLogicalAxisBlock)) {
6076 0 : minBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
6077 0 : boxSizingAdjust.BSize(aWM), minBSizeCoord);
6078 0 : } else {
6079 : minBSize = 0;
6080 : }
6081 :
6082 : NS_ASSERTION(aCBSize.ISize(aWM) != NS_UNCONSTRAINEDSIZE,
6083 0 : "Our containing block must not have unconstrained inline-size!");
6084 :
6085 : // Now calculate the used values for iSize and bSize:
6086 :
6087 : if (isAutoISize) {
6088 0 : if (isAutoBSize) {
6089 0 :
6090 : // 'auto' iSize, 'auto' bSize
6091 :
6092 : // Get tentative values - CSS 2.1 sections 10.3.2 and 10.6.2:
6093 :
6094 : nscoord tentISize, tentBSize;
6095 :
6096 : if (hasIntrinsicISize) {
6097 0 : tentISize = intrinsicISize;
6098 : } else if (hasIntrinsicBSize && logicalRatio.BSize(aWM) > 0) {
6099 0 : tentISize = NSCoordMulDiv(intrinsicBSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
6100 0 : } else if (logicalRatio.ISize(aWM) > 0) {
6101 0 : tentISize = aCBSize.ISize(aWM) - boxSizingToMarginEdgeISize; // XXX scrollbar?
6102 0 : if (tentISize < 0) tentISize = 0;
6103 0 : } else {
6104 : tentISize = nsPresContext::CSSPixelsToAppUnits(300);
6105 0 : }
6106 :
6107 : // If we need to clamp the inline size to fit the CB, we use the 'stretch'
6108 : // or 'normal' codepath. We use the ratio-preserving 'normal' codepath
6109 : // unless we have 'stretch' in the other axis.
6110 : if ((aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) &&
6111 0 : stretchI != eStretch && tentISize > iSize) {
6112 0 : stretchI = (stretchB == eStretch ? eStretch : eStretchPreservingRatio);
6113 0 : }
6114 :
6115 : if (hasIntrinsicBSize) {
6116 0 : tentBSize = intrinsicBSize;
6117 : } else if (logicalRatio.ISize(aWM) > 0) {
6118 0 : tentBSize = NSCoordMulDiv(tentISize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
6119 0 : } else {
6120 : tentBSize = nsPresContext::CSSPixelsToAppUnits(150);
6121 0 : }
6122 :
6123 : // (ditto the comment about clamping the inline size above)
6124 : if ((aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize) &&
6125 0 : stretchB != eStretch && tentBSize > bSize) {
6126 0 : stretchB = (stretchI == eStretch ? eStretch : eStretchPreservingRatio);
6127 0 : }
6128 :
6129 : if (aIntrinsicRatio != nsSize(0, 0)) {
6130 0 : if (stretchI == eStretch) {
6131 0 : tentISize = iSize; // * / 'stretch'
6132 0 : if (stretchB == eStretch) {
6133 0 : tentBSize = bSize; // 'stretch' / 'stretch'
6134 : } else if (stretchB == eStretchPreservingRatio && logicalRatio.ISize(aWM) > 0) {
6135 0 : // 'normal' / 'stretch'
6136 : tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
6137 0 : }
6138 : } else if (stretchB == eStretch) {
6139 0 : tentBSize = bSize; // 'stretch' / * (except 'stretch')
6140 0 : if (stretchI == eStretchPreservingRatio && logicalRatio.BSize(aWM) > 0) {
6141 0 : // 'stretch' / 'normal'
6142 : tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
6143 0 : }
6144 : } else if (stretchI == eStretchPreservingRatio) {
6145 0 : tentISize = iSize; // * (except 'stretch') / 'normal'
6146 0 : if (logicalRatio.ISize(aWM) > 0) {
6147 0 : tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
6148 0 : }
6149 : if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
6150 0 : // Stretch within the CB size with preserved intrinsic ratio.
6151 : tentBSize = bSize; // 'normal' / 'normal'
6152 0 : if (logicalRatio.BSize(aWM) > 0) {
6153 0 : tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
6154 0 : }
6155 : }
6156 : } else if (stretchB == eStretchPreservingRatio) {
6157 0 : tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
6158 0 : if (logicalRatio.BSize(aWM) > 0) {
6159 0 : tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
6160 0 : }
6161 : }
6162 : }
6163 :
6164 : // ComputeAutoSizeWithIntrinsicDimensions preserves the ratio when applying
6165 : // the min/max-size. We don't want that when we have 'stretch' in either
6166 : // axis because tentISize/tentBSize is likely not according to ratio now.
6167 : if (aIntrinsicRatio != nsSize(0, 0) &&
6168 0 : stretchI != eStretch && stretchB != eStretch) {
6169 0 : nsSize autoSize = nsLayoutUtils::
6170 : ComputeAutoSizeWithIntrinsicDimensions(minISize, minBSize,
6171 : maxISize, maxBSize,
6172 : tentISize, tentBSize);
6173 0 : // The nsSize that ComputeAutoSizeWithIntrinsicDimensions returns will
6174 : // actually contain logical values if the parameters passed to it were
6175 : // logical coordinates, so we do NOT perform a physical-to-logical
6176 : // conversion here, but just assign the fields directly to our result.
6177 : iSize = autoSize.width;
6178 0 : bSize = autoSize.height;
6179 0 : } else {
6180 : // Not honoring an intrinsic ratio: clamp the dimensions independently.
6181 : iSize = NS_CSS_MINMAX(tentISize, minISize, maxISize);
6182 0 : bSize = NS_CSS_MINMAX(tentBSize, minBSize, maxBSize);
6183 : }
6184 : } else {
6185 :
6186 : // 'auto' iSize, non-'auto' bSize
6187 : bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
6188 0 : if (stretchI != eStretch) {
6189 0 : if (logicalRatio.BSize(aWM) > 0) {
6190 0 : iSize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
6191 0 : } else if (hasIntrinsicISize) {
6192 0 : if (!((aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) &&
6193 0 : intrinsicISize > iSize)) {
6194 : iSize = intrinsicISize;
6195 0 : } // else - leave iSize as is to fill the CB
6196 : } else {
6197 : iSize = nsPresContext::CSSPixelsToAppUnits(300);
6198 0 : }
6199 : } // else - leave iSize as is to fill the CB
6200 : iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
6201 :
6202 : }
6203 : } else {
6204 : if (isAutoBSize) {
6205 0 :
6206 : // non-'auto' iSize, 'auto' bSize
6207 : iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
6208 0 : if (stretchB != eStretch) {
6209 0 : if (logicalRatio.ISize(aWM) > 0) {
6210 0 : bSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
6211 0 : } else if (hasIntrinsicBSize) {
6212 0 : if (!((aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize) &&
6213 0 : intrinsicBSize > bSize)) {
6214 : bSize = intrinsicBSize;
6215 0 : } // else - leave bSize as is to fill the CB
6216 : } else {
6217 : bSize = nsPresContext::CSSPixelsToAppUnits(150);
6218 0 : }
6219 : } // else - leave bSize as is to fill the CB
6220 : bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
6221 :
6222 : } else {
6223 :
6224 : // non-'auto' iSize, non-'auto' bSize
6225 : iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
6226 0 : bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
6227 :
6228 : }
6229 : }
6230 :
6231 : return LogicalSize(aWM, iSize, bSize);
6232 0 : }
6233 :
6234 : nsRect
6235 : nsIFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const
6236 0 : {
6237 : return GetVisualOverflowRect();
6238 0 : }
6239 :
6240 : nsRect
6241 : nsFrame::ComputeSimpleTightBounds(DrawTarget* aDrawTarget) const
6242 0 : {
6243 : if (StyleOutline()->ShouldPaintOutline() || StyleBorder()->HasBorder() ||
6244 0 : !StyleBackground()->IsTransparent(this) ||
6245 0 : StyleDisplay()->mAppearance) {
6246 0 : // Not necessarily tight, due to clipping, negative
6247 : // outline-offset, and lots of other issues, but that's OK
6248 : return GetVisualOverflowRect();
6249 0 : }
6250 :
6251 : nsRect r(0, 0, 0, 0);
6252 0 : ChildListIterator lists(this);
6253 0 : for (; !lists.IsDone(); lists.Next()) {
6254 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
6255 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
6256 0 : nsIFrame* child = childFrames.get();
6257 0 : r.UnionRect(r, child->ComputeTightBounds(aDrawTarget) + child->GetPosition());
6258 0 : }
6259 : }
6260 : return r;
6261 0 : }
6262 :
6263 : /* virtual */ nsresult
6264 : nsIFrame::GetPrefWidthTightBounds(gfxContext* aContext,
6265 0 : nscoord* aX,
6266 : nscoord* aXMost)
6267 : {
6268 : return NS_ERROR_NOT_IMPLEMENTED;
6269 0 : }
6270 :
6271 : /* virtual */
6272 : LogicalSize
6273 : nsFrame::ComputeAutoSize(gfxContext* aRenderingContext,
6274 0 : WritingMode aWM,
6275 : const mozilla::LogicalSize& aCBSize,
6276 : nscoord aAvailableISize,
6277 : const mozilla::LogicalSize& aMargin,
6278 : const mozilla::LogicalSize& aBorder,
6279 : const mozilla::LogicalSize& aPadding,
6280 : ComputeSizeFlags aFlags)
6281 : {
6282 : // Use basic shrink-wrapping as a default implementation.
6283 : LogicalSize result(aWM, 0xdeadbeef, NS_UNCONSTRAINEDSIZE);
6284 33 :
6285 : // don't bother setting it if the result won't be used
6286 : if (StylePosition()->ISize(aWM).GetUnit() == eStyleUnit_Auto) {
6287 66 : nscoord availBased = aAvailableISize - aMargin.ISize(aWM) -
6288 0 : aBorder.ISize(aWM) - aPadding.ISize(aWM);
6289 66 : result.ISize(aWM) = ShrinkWidthToFit(aRenderingContext, availBased, aFlags);
6290 33 : }
6291 : return result;
6292 33 : }
6293 :
6294 : nscoord
6295 : nsFrame::ShrinkWidthToFit(gfxContext* aRenderingContext,
6296 51 : nscoord aISizeInCB,
6297 : ComputeSizeFlags aFlags)
6298 : {
6299 : // If we're a container for font size inflation, then shrink
6300 : // wrapping inside of us should not apply font size inflation.
6301 : AutoMaybeDisableFontInflation an(this);
6302 102 :
6303 : nscoord result;
6304 : nscoord minISize = GetMinISize(aRenderingContext);
6305 51 : if (minISize > aISizeInCB) {
6306 0 : const bool clamp = aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize;
6307 0 : result = MOZ_UNLIKELY(clamp) ? aISizeInCB : minISize;
6308 0 : } else {
6309 : nscoord prefISize = GetPrefISize(aRenderingContext);
6310 51 : if (prefISize > aISizeInCB) {
6311 0 : result = aISizeInCB;
6312 : } else {
6313 : result = prefISize;
6314 0 : }
6315 : }
6316 : return result;
6317 0 : }
6318 :
6319 : nscoord
6320 : nsIFrame::ComputeISizeValue(gfxContext* aRenderingContext,
6321 27 : nscoord aContainingBlockISize,
6322 : nscoord aContentEdgeToBoxSizing,
6323 : nscoord aBoxSizingToMarginEdge,
6324 : const nsStyleCoord& aCoord,
6325 : ComputeSizeFlags aFlags)
6326 : {
6327 : MOZ_ASSERT(aRenderingContext, "non-null rendering context expected");
6328 27 : LAYOUT_WARN_IF_FALSE(aContainingBlockISize != NS_UNCONSTRAINEDSIZE,
6329 27 : "have unconstrained inline-size; this should only result from "
6330 : "very large sizes, not attempts at intrinsic inline-size "
6331 : "calculation");
6332 : MOZ_ASSERT(aContainingBlockISize >= 0,
6333 27 : "inline-size less than zero");
6334 :
6335 : nscoord result;
6336 : if (aCoord.IsCoordPercentCalcUnit()) {
6337 27 : result = aCoord.ComputeCoordPercentCalc(aContainingBlockISize);
6338 27 : // The result of a calc() expression might be less than 0; we
6339 : // should clamp at runtime (below). (Percentages and coords that
6340 : // are less than 0 have already been dropped by the parser.)
6341 : result -= aContentEdgeToBoxSizing;
6342 27 : } else {
6343 : MOZ_ASSERT(eStyleUnit_Enumerated == aCoord.GetUnit());
6344 0 : // If 'this' is a container for font size inflation, then shrink
6345 : // wrapping inside of it should not apply font size inflation.
6346 : AutoMaybeDisableFontInflation an(this);
6347 0 :
6348 : int32_t val = aCoord.GetIntValue();
6349 0 : switch (val) {
6350 0 : case NS_STYLE_WIDTH_MAX_CONTENT:
6351 : result = GetPrefISize(aRenderingContext);
6352 0 : NS_ASSERTION(result >= 0, "inline-size less than zero");
6353 0 : break;
6354 : case NS_STYLE_WIDTH_MIN_CONTENT:
6355 : result = GetMinISize(aRenderingContext);
6356 0 : NS_ASSERTION(result >= 0, "inline-size less than zero");
6357 0 : if (MOZ_UNLIKELY(aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
6358 0 : auto available = aContainingBlockISize -
6359 0 : (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
6360 0 : result = std::min(available, result);
6361 0 : }
6362 : break;
6363 : case NS_STYLE_WIDTH_FIT_CONTENT:
6364 : {
6365 : nscoord pref = GetPrefISize(aRenderingContext),
6366 0 : min = GetMinISize(aRenderingContext),
6367 0 : fill = aContainingBlockISize -
6368 0 : (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
6369 0 : if (MOZ_UNLIKELY(aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
6370 0 : min = std::min(min, fill);
6371 0 : }
6372 : result = std::max(min, std::min(pref, fill));
6373 0 : NS_ASSERTION(result >= 0, "inline-size less than zero");
6374 0 : }
6375 : break;
6376 0 : case NS_STYLE_WIDTH_AVAILABLE:
6377 : result = aContainingBlockISize -
6378 0 : (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
6379 0 : }
6380 : }
6381 :
6382 : return std::max(0, result);
6383 0 : }
6384 :
6385 : void
6386 : nsFrame::DidReflow(nsPresContext* aPresContext,
6387 290 : const ReflowInput* aReflowInput)
6388 : {
6389 : NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, ("nsFrame::DidReflow"));
6390 0 :
6391 : SVGObserverUtils::InvalidateDirectRenderingObservers(this,
6392 290 : SVGObserverUtils::INVALIDATE_REFLOW);
6393 290 :
6394 : RemoveStateBits(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW |
6395 0 : NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN);
6396 290 :
6397 : // Notify the percent bsize observer if there is a percent bsize.
6398 : // The observer may be able to initiate another reflow with a computed
6399 : // bsize. This happens in the case where a table cell has no computed
6400 : // bsize but can fabricate one when the cell bsize is known.
6401 : if (aReflowInput && aReflowInput->mPercentBSizeObserver &&
6402 290 : !GetPrevInFlow()) {
6403 0 : const nsStyleCoord &bsize =
6404 : aReflowInput->mStylePosition->BSize(aReflowInput->GetWritingMode());
6405 0 : if (bsize.HasPercent()) {
6406 0 : aReflowInput->mPercentBSizeObserver->NotifyPercentBSize(*aReflowInput);
6407 0 : }
6408 : }
6409 :
6410 : aPresContext->ReflowedFrame();
6411 0 : }
6412 0 :
6413 : void
6414 : nsFrame::FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext,
6415 0 : ReflowOutput& aDesiredSize,
6416 : const ReflowInput& aReflowInput,
6417 : nsReflowStatus& aStatus,
6418 : bool aConstrainBSize)
6419 : {
6420 : ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowInput, aStatus, aConstrainBSize);
6421 0 :
6422 : FinishAndStoreOverflow(&aDesiredSize, aReflowInput.mStyleDisplay);
6423 0 : }
6424 79 :
6425 : void
6426 : nsFrame::ReflowAbsoluteFrames(nsPresContext* aPresContext,
6427 106 : ReflowOutput& aDesiredSize,
6428 : const ReflowInput& aReflowInput,
6429 : nsReflowStatus& aStatus,
6430 : bool aConstrainBSize)
6431 : {
6432 : if (HasAbsolutelyPositionedChildren()) {
6433 0 : nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock();
6434 8 :
6435 : // Let the absolutely positioned container reflow any absolutely positioned
6436 : // child frames that need to be reflowed
6437 :
6438 : // The containing block for the abs pos kids is formed by our padding edge.
6439 : nsMargin usedBorder = GetUsedBorder();
6440 0 : nscoord containingBlockWidth =
6441 : std::max(0, aDesiredSize.Width() - usedBorder.LeftRight());
6442 24 : nscoord containingBlockHeight =
6443 : std::max(0, aDesiredSize.Height() - usedBorder.TopBottom());
6444 24 : nsContainerFrame* container = do_QueryFrame(this);
6445 0 : NS_ASSERTION(container, "Abs-pos children only supported on container frames for now");
6446 8 :
6447 : nsRect containingBlock(0, 0, containingBlockWidth, containingBlockHeight);
6448 16 : AbsPosReflowFlags flags =
6449 : AbsPosReflowFlags::eCBWidthAndHeightChanged; // XXX could be optimized
6450 8 : if (aConstrainBSize) {
6451 8 : flags |= AbsPosReflowFlags::eConstrainHeight;
6452 : }
6453 : absoluteContainer->Reflow(container, aPresContext, aReflowInput, aStatus,
6454 0 : containingBlock, flags,
6455 : &aDesiredSize.mOverflowAreas);
6456 8 : }
6457 : }
6458 0 :
6459 : void
6460 : nsFrame::PushDirtyBitToAbsoluteFrames()
6461 0 : {
6462 : if (!(GetStateBits() & NS_FRAME_IS_DIRTY)) {
6463 0 : return; // No dirty bit to push.
6464 : }
6465 : if (!HasAbsolutelyPositionedChildren()) {
6466 0 : return; // No absolute children to push to.
6467 : }
6468 : GetAbsoluteContainingBlock()->MarkAllFramesDirty();
6469 0 : }
6470 :
6471 : /* virtual */ bool
6472 : nsFrame::CanContinueTextRun() const
6473 0 : {
6474 : // By default, a frame will *not* allow a text run to be continued
6475 : // through it.
6476 : return false;
6477 0 : }
6478 :
6479 : void
6480 : nsFrame::Reflow(nsPresContext* aPresContext,
6481 0 : ReflowOutput& aDesiredSize,
6482 : const ReflowInput& aReflowInput,
6483 : nsReflowStatus& aStatus)
6484 : {
6485 : MarkInReflow();
6486 0 : DO_GLOBAL_REFLOW_COUNT("nsFrame");
6487 0 : MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
6488 0 : aDesiredSize.ClearSize();
6489 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
6490 0 : }
6491 0 :
6492 : bool
6493 : nsIFrame::IsContentDisabled() const
6494 5 : {
6495 : // FIXME(emilio): Doing this via CSS means callers must ensure the style is up
6496 : // to date, and they don't!
6497 : if (StyleUserInterface()->mUserInput == StyleUserInput::None) {
6498 5 : return true;
6499 : }
6500 :
6501 : auto* element = nsGenericHTMLElement::FromNodeOrNull(GetContent());
6502 0 : return element && element->IsDisabled();
6503 5 : }
6504 :
6505 : nsresult
6506 : nsFrame::CharacterDataChanged(const CharacterDataChangeInfo&)
6507 0 : {
6508 : NS_NOTREACHED("should only be called for text frames");
6509 0 : return NS_OK;
6510 0 : }
6511 :
6512 : nsresult
6513 : nsFrame::AttributeChanged(int32_t aNameSpaceID,
6514 4 : nsAtom* aAttribute,
6515 : int32_t aModType)
6516 : {
6517 : return NS_OK;
6518 0 : }
6519 :
6520 : // Flow member functions
6521 :
6522 : nsSplittableType
6523 : nsFrame::GetSplittableType() const
6524 0 : {
6525 : return NS_FRAME_NOT_SPLITTABLE;
6526 0 : }
6527 :
6528 : nsIFrame* nsFrame::GetPrevContinuation() const
6529 54 : {
6530 : return nullptr;
6531 0 : }
6532 :
6533 : void
6534 : nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation)
6535 0 : {
6536 : MOZ_ASSERT(false, "not splittable");
6537 0 : }
6538 :
6539 : nsIFrame* nsFrame::GetNextContinuation() const
6540 33 : {
6541 : return nullptr;
6542 33 : }
6543 :
6544 : void
6545 : nsFrame::SetNextContinuation(nsIFrame*)
6546 0 : {
6547 : MOZ_ASSERT(false, "not splittable");
6548 0 : }
6549 :
6550 : nsIFrame* nsFrame::GetPrevInFlowVirtual() const
6551 0 : {
6552 : return nullptr;
6553 0 : }
6554 :
6555 : void
6556 : nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow)
6557 0 : {
6558 : MOZ_ASSERT(false, "not splittable");
6559 0 : }
6560 :
6561 : nsIFrame* nsFrame::GetNextInFlowVirtual() const
6562 9 : {
6563 : return nullptr;
6564 0 : }
6565 :
6566 : void
6567 : nsFrame::SetNextInFlow(nsIFrame*)
6568 0 : {
6569 : MOZ_ASSERT(false, "not splittable");
6570 0 : }
6571 :
6572 : nsIFrame* nsIFrame::GetTailContinuation()
6573 5 : {
6574 : nsIFrame* frame = this;
6575 5 : while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
6576 0 : frame = frame->GetPrevContinuation();
6577 0 : NS_ASSERTION(frame, "first continuation can't be overflow container");
6578 0 : }
6579 : for (nsIFrame* next = frame->GetNextContinuation();
6580 0 : next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
6581 5 : next = frame->GetNextContinuation()) {
6582 0 : frame = next;
6583 0 : }
6584 :
6585 : MOZ_ASSERT(frame, "illegal state in continuation chain.");
6586 1 : return frame;
6587 5 : }
6588 :
6589 : // Associated view object
6590 : void
6591 : nsIFrame::SetView(nsView* aView)
6592 61 : {
6593 : if (aView) {
6594 61 : aView->SetFrame(this);
6595 122 :
6596 : #ifdef DEBUG
6597 : LayoutFrameType frameType = Type();
6598 61 : NS_ASSERTION(frameType == LayoutFrameType::SubDocument ||
6599 1 : frameType == LayoutFrameType::ListControl ||
6600 : frameType == LayoutFrameType::Object ||
6601 : frameType == LayoutFrameType::Viewport ||
6602 : frameType == LayoutFrameType::MenuPopup,
6603 : "Only specific frame types can have an nsView");
6604 : #endif
6605 :
6606 : // Store the view on the frame.
6607 : SetViewInternal(aView);
6608 1 :
6609 : // Set the frame state bit that says the frame has a view
6610 : AddStateBits(NS_FRAME_HAS_VIEW);
6611 61 :
6612 : // Let all of the ancestors know they have a descendant with a view.
6613 : for (nsIFrame* f = GetParent();
6614 244 : f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
6615 0 : f = f->GetParent())
6616 : f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
6617 61 : } else {
6618 : MOZ_ASSERT_UNREACHABLE("Destroying a view while the frame is alive?");
6619 0 : RemoveStateBits(NS_FRAME_HAS_VIEW);
6620 : SetViewInternal(nullptr);
6621 : }
6622 : }
6623 61 :
6624 : // Find the first geometric parent that has a view
6625 : nsIFrame* nsIFrame::GetAncestorWithView() const
6626 0 : {
6627 : for (nsIFrame* f = GetParent(); nullptr != f; f = f->GetParent()) {
6628 0 : if (f->HasView()) {
6629 0 : return f;
6630 : }
6631 : }
6632 : return nullptr;
6633 : }
6634 :
6635 : template<nsPoint (nsIFrame::* PositionGetter)() const>
6636 : static nsPoint OffsetCalculator(const nsIFrame* aThis, const nsIFrame* aOther)
6637 0 : {
6638 : MOZ_ASSERT(aOther,
6639 1 : "Must have frame for destination coordinate system!");
6640 :
6641 : NS_ASSERTION(aThis->PresContext() == aOther->PresContext(),
6642 0 : "GetOffsetTo called on frames in different documents");
6643 :
6644 : nsPoint offset(0, 0);
6645 0 : const nsIFrame* f;
6646 : for (f = aThis; f != aOther && f; f = f->GetParent()) {
6647 2270 : offset += (f->*PositionGetter)();
6648 0 : }
6649 :
6650 : if (f != aOther) {
6651 1081 : // Looks like aOther wasn't an ancestor of |this|. So now we have
6652 : // the root-frame-relative position of |this| in |offset|. Convert back
6653 : // to the coordinates of aOther
6654 : while (aOther) {
6655 0 : offset -= (aOther->*PositionGetter)();
6656 0 : aOther = aOther->GetParent();
6657 0 : }
6658 : }
6659 :
6660 : return offset;
6661 0 : }
6662 :
6663 : nsPoint
6664 : nsIFrame::GetOffsetTo(const nsIFrame* aOther) const
6665 10 : {
6666 : return OffsetCalculator<&nsIFrame::GetPosition>(this, aOther);
6667 1049 : }
6668 :
6669 : nsPoint
6670 : nsIFrame::GetOffsetToIgnoringScrolling(const nsIFrame* aOther) const
6671 32 : {
6672 : return OffsetCalculator<&nsIFrame::GetPositionIgnoringScrolling>(this, aOther);
6673 0 : }
6674 :
6675 : nsPoint nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther) const
6676 0 : {
6677 : return GetOffsetToCrossDoc(aOther, PresContext()->AppUnitsPerDevPixel());
6678 335 : }
6679 :
6680 : nsPoint
6681 : nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const
6682 357 : {
6683 : MOZ_ASSERT(aOther,
6684 357 : "Must have frame for destination coordinate system!");
6685 : NS_ASSERTION(PresContext()->GetRootPresContext() ==
6686 714 : aOther->PresContext()->GetRootPresContext(),
6687 : "trying to get the offset between frames in different document "
6688 : "hierarchies?");
6689 : if (PresContext()->GetRootPresContext() !=
6690 1 : aOther->PresContext()->GetRootPresContext()) {
6691 1 : // crash right away, we are almost certainly going to crash anyway.
6692 : MOZ_CRASH("trying to get the offset between frames in different "
6693 0 : "document hierarchies?");
6694 : }
6695 :
6696 : const nsIFrame* root = nullptr;
6697 357 : // offset will hold the final offset
6698 : // docOffset holds the currently accumulated offset at the current APD, it
6699 : // will be converted and added to offset when the current APD changes.
6700 : nsPoint offset(0, 0), docOffset(0, 0);
6701 0 : const nsIFrame* f = this;
6702 357 : int32_t currAPD = PresContext()->AppUnitsPerDevPixel();
6703 357 : while (f && f != aOther) {
6704 0 : docOffset += f->GetPosition();
6705 1576 : nsIFrame* parent = f->GetParent();
6706 1576 : if (parent) {
6707 0 : f = parent;
6708 : } else {
6709 : nsPoint newOffset(0, 0);
6710 0 : root = f;
6711 25 : f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
6712 25 : int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
6713 0 : if (!f || newAPD != currAPD) {
6714 25 : // Convert docOffset to the right APD and add it to offset.
6715 : offset += docOffset.ScaleToOtherAppUnits(currAPD, aAPD);
6716 22 : docOffset.x = docOffset.y = 0;
6717 0 : }
6718 : currAPD = newAPD;
6719 0 : docOffset += newOffset;
6720 25 : }
6721 : }
6722 : if (f == aOther) {
6723 0 : offset += docOffset.ScaleToOtherAppUnits(currAPD, aAPD);
6724 335 : } else {
6725 : // Looks like aOther wasn't an ancestor of |this|. So now we have
6726 : // the root-document-relative position of |this| in |offset|. Subtract the
6727 : // root-document-relative position of |aOther| from |offset|.
6728 : // This call won't try to recurse again because root is an ancestor of
6729 : // aOther.
6730 : nsPoint negOffset = aOther->GetOffsetToCrossDoc(root, aAPD);
6731 22 : offset -= negOffset;
6732 22 : }
6733 :
6734 : return offset;
6735 0 : }
6736 :
6737 : CSSIntRect nsIFrame::GetScreenRect() const
6738 0 : {
6739 : return CSSIntRect::FromAppUnitsToNearest(GetScreenRectInAppUnits());
6740 0 : }
6741 :
6742 : nsRect nsIFrame::GetScreenRectInAppUnits() const
6743 0 : {
6744 : nsPresContext* presContext = PresContext();
6745 0 : nsIFrame* rootFrame =
6746 : presContext->PresShell()->GetRootFrame();
6747 0 : nsPoint rootScreenPos(0, 0);
6748 0 : nsPoint rootFrameOffsetInParent(0, 0);
6749 0 : nsIFrame* rootFrameParent =
6750 : nsLayoutUtils::GetCrossDocParentFrame(rootFrame, &rootFrameOffsetInParent);
6751 0 : if (rootFrameParent) {
6752 0 : nsRect parentScreenRectAppUnits = rootFrameParent->GetScreenRectInAppUnits();
6753 0 : nsPresContext* parentPresContext = rootFrameParent->PresContext();
6754 0 : double parentScale = double(presContext->AppUnitsPerDevPixel())/
6755 0 : parentPresContext->AppUnitsPerDevPixel();
6756 0 : nsPoint rootPt = parentScreenRectAppUnits.TopLeft() + rootFrameOffsetInParent;
6757 0 : rootScreenPos.x = NS_round(parentScale*rootPt.x);
6758 0 : rootScreenPos.y = NS_round(parentScale*rootPt.y);
6759 0 : } else {
6760 : nsCOMPtr<nsIWidget> rootWidget;
6761 0 : presContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(rootWidget));
6762 0 : if (rootWidget) {
6763 0 : LayoutDeviceIntPoint rootDevPx = rootWidget->WidgetToScreenOffset();
6764 0 : rootScreenPos.x = presContext->DevPixelsToAppUnits(rootDevPx.x);
6765 0 : rootScreenPos.y = presContext->DevPixelsToAppUnits(rootDevPx.y);
6766 0 : }
6767 : }
6768 :
6769 : return nsRect(rootScreenPos + GetOffsetTo(rootFrame), GetSize());
6770 0 : }
6771 :
6772 : // Returns the offset from this frame to the closest geometric parent that
6773 : // has a view. Also returns the containing view or null in case of error
6774 : void
6775 : nsIFrame::GetOffsetFromView(nsPoint& aOffset, nsView** aView) const
6776 0 : {
6777 : MOZ_ASSERT(nullptr != aView, "null OUT parameter pointer");
6778 0 : nsIFrame* frame = const_cast<nsIFrame*>(this);
6779 0 :
6780 : *aView = nullptr;
6781 0 : aOffset.MoveTo(0, 0);
6782 0 : do {
6783 0 : aOffset += frame->GetPosition();
6784 0 : frame = frame->GetParent();
6785 0 : } while (frame && !frame->HasView());
6786 0 :
6787 : if (frame) {
6788 0 : *aView = frame->GetView();
6789 0 : }
6790 : }
6791 0 :
6792 : nsIWidget*
6793 : nsIFrame::GetNearestWidget() const
6794 0 : {
6795 : return GetClosestView()->GetNearestWidget(nullptr);
6796 243 : }
6797 :
6798 : nsIWidget*
6799 : nsIFrame::GetNearestWidget(nsPoint& aOffset) const
6800 0 : {
6801 : nsPoint offsetToView;
6802 0 : nsPoint offsetToWidget;
6803 0 : nsIWidget* widget =
6804 : GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
6805 0 : aOffset = offsetToView + offsetToWidget;
6806 0 : return widget;
6807 0 : }
6808 :
6809 : Matrix4x4Flagged
6810 : nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
6811 0 : nsIFrame** aOutAncestor,
6812 : uint32_t aFlags)
6813 : {
6814 : MOZ_ASSERT(aOutAncestor, "Need a place to put the ancestor!");
6815 0 :
6816 : /* If we're transformed, we want to hand back the combination
6817 : * transform/translate matrix that will apply our current transform, then
6818 : * shift us to our parent.
6819 : */
6820 : if (IsTransformed()) {
6821 0 : /* Compute the delta to the parent, which we need because we are converting
6822 : * coordinates to our parent.
6823 : */
6824 : NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
6825 0 : "Cannot transform the viewport frame!");
6826 : int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? PresContext()->AppUnitsPerCSSPixel()
6827 0 : : PresContext()->AppUnitsPerDevPixel());
6828 0 :
6829 : Matrix4x4 result = nsDisplayTransform::GetResultingTransformMatrix(this,
6830 : nsPoint(0,0), scaleFactor,
6831 0 : nsDisplayTransform::INCLUDE_PERSPECTIVE|nsDisplayTransform::OFFSET_BY_ORIGIN,
6832 : nullptr);
6833 0 : *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
6834 0 : nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
6835 0 : /* Combine the raw transform with a translation to our parent. */
6836 : result.PostTranslate(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
6837 : NSAppUnitsToFloatPixels(delta.y, scaleFactor),
6838 : 0.0f);
6839 0 :
6840 : return result;
6841 0 : }
6842 :
6843 : if (nsLayoutUtils::IsPopup(this) && IsListControlFrame()) {
6844 0 : nsPresContext* presContext = PresContext();
6845 0 : nsIFrame* docRootFrame = presContext->PresShell()->GetRootFrame();
6846 0 :
6847 : // Compute a matrix that transforms from the popup widget to the toplevel
6848 : // widget. We use the widgets because they're the simplest and most
6849 : // accurate approach --- this should work no matter how the widget position
6850 : // was chosen.
6851 : nsIWidget* widget = GetView()->GetWidget();
6852 0 : nsPresContext* rootPresContext = PresContext()->GetRootPresContext();
6853 0 : // Maybe the widget hasn't been created yet? Popups without widgets are
6854 : // treated as regular frames. That should work since they'll be rendered
6855 : // as part of the page if they're rendered at all.
6856 : if (widget && rootPresContext) {
6857 0 : nsIWidget* toplevel = rootPresContext->GetNearestWidget();
6858 0 : if (toplevel) {
6859 0 : LayoutDeviceIntRect screenBounds = widget->GetClientBounds();
6860 0 : LayoutDeviceIntRect toplevelScreenBounds = toplevel->GetClientBounds();
6861 0 : LayoutDeviceIntPoint translation =
6862 : screenBounds.TopLeft() - toplevelScreenBounds.TopLeft();
6863 0 :
6864 : Matrix4x4 transformToTop;
6865 0 : transformToTop._41 = translation.x;
6866 0 : transformToTop._42 = translation.y;
6867 0 :
6868 : *aOutAncestor = docRootFrame;
6869 0 : Matrix4x4 docRootTransformToTop =
6870 : nsLayoutUtils::GetTransformToAncestor(docRootFrame, nullptr).GetMatrix();
6871 0 : if (docRootTransformToTop.IsSingular()) {
6872 0 : NS_WARNING("Containing document is invisible, we can't compute a valid transform");
6873 0 : } else {
6874 : docRootTransformToTop.Invert();
6875 0 : return transformToTop * docRootTransformToTop;
6876 0 : }
6877 : }
6878 : }
6879 : }
6880 :
6881 : *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
6882 121 :
6883 : /* Otherwise, we're not transformed. In that case, we'll walk up the frame
6884 : * tree until we either hit the root frame or something that may be
6885 : * transformed. We'll then change coordinates into that frame, since we're
6886 : * guaranteed that nothing in-between can be transformed. First, however,
6887 : * we have to check to see if we have a parent. If not, we'll set the
6888 : * outparam to null (indicating that there's nothing left) and will hand back
6889 : * the identity matrix.
6890 : */
6891 : if (!*aOutAncestor)
6892 121 : return Matrix4x4();
6893 0 :
6894 : /* Keep iterating while the frame can't possibly be transformed. */
6895 : nsIFrame* current = this;
6896 : while (!(*aOutAncestor)->IsTransformed() &&
6897 0 : !nsLayoutUtils::IsPopup(*aOutAncestor) &&
6898 1546 : *aOutAncestor != aStopAtAncestor &&
6899 2198 : (!(aFlags & STOP_AT_STACKING_CONTEXT_AND_DISPLAY_PORT) ||
6900 652 : (!(*aOutAncestor)->IsStackingContext() && !nsLayoutUtils::FrameHasDisplayPort(*aOutAncestor, current)))) {
6901 0 : /* If no parent, stop iterating. Otherwise, update the ancestor. */
6902 : nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
6903 0 : if (!parent)
6904 652 : break;
6905 :
6906 : current = *aOutAncestor;
6907 0 : *aOutAncestor = parent;
6908 0 : }
6909 :
6910 : NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?");
6911 121 :
6912 : /* Translate from this frame to our ancestor, if it exists. That's the
6913 : * entire transform, so we're done.
6914 : */
6915 : nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
6916 121 : int32_t scaleFactor = ((aFlags & IN_CSS_UNITS) ? PresContext()->AppUnitsPerCSSPixel()
6917 242 : : PresContext()->AppUnitsPerDevPixel());
6918 242 : return Matrix4x4::Translation(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
6919 0 : NSAppUnitsToFloatPixels(delta.y, scaleFactor),
6920 : 0.0f);
6921 0 : }
6922 :
6923 : static void InvalidateRenderingObservers(nsIFrame* aDisplayRoot, nsIFrame* aFrame, bool aFrameChanged = true)
6924 116 : {
6925 : MOZ_ASSERT(aDisplayRoot == nsLayoutUtils::GetDisplayRootFrame(aFrame));
6926 116 : SVGObserverUtils::InvalidateDirectRenderingObservers(aFrame);
6927 0 : nsIFrame* parent = aFrame;
6928 0 : while (parent != aDisplayRoot &&
6929 0 : (parent = nsLayoutUtils::GetCrossDocParentFrame(parent)) &&
6930 572 : !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
6931 0 : SVGObserverUtils::InvalidateDirectRenderingObservers(parent);
6932 198 : }
6933 :
6934 : if (!aFrameChanged) {
6935 1 : return;
6936 : }
6937 :
6938 : aFrame->MarkNeedsDisplayItemRebuild();
6939 66 : }
6940 :
6941 : static void
6942 : SchedulePaintInternal(nsIFrame* aDisplayRoot, nsIFrame* aFrame,
6943 220 : nsIFrame::PaintType aType = nsIFrame::PAINT_DEFAULT)
6944 : {
6945 : MOZ_ASSERT(aDisplayRoot == nsLayoutUtils::GetDisplayRootFrame(aFrame));
6946 220 : nsPresContext* pres = aDisplayRoot->PresContext()->GetRootPresContext();
6947 220 :
6948 : // No need to schedule a paint for an external document since they aren't
6949 : // painted directly.
6950 : if (!pres || (pres->Document() && pres->Document()->IsResourceDoc())) {
6951 220 : return;
6952 : }
6953 : if (!pres->GetContainerWeak()) {
6954 0 : NS_WARNING("Shouldn't call SchedulePaint in a detached pres context");
6955 0 : return;
6956 0 : }
6957 :
6958 : pres->PresShell()->ScheduleViewManagerFlush(aType == nsIFrame::PAINT_DELAYED_COMPRESS ?
6959 0 : nsIPresShell::PAINT_DELAYED_COMPRESS :
6960 : nsIPresShell::PAINT_DEFAULT);
6961 0 :
6962 : if (aType == nsIFrame::PAINT_DELAYED_COMPRESS) {
6963 0 : return;
6964 : }
6965 :
6966 : if (aType == nsIFrame::PAINT_DEFAULT) {
6967 131 : aDisplayRoot->AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
6968 : }
6969 : }
6970 :
6971 : static void InvalidateFrameInternal(nsIFrame *aFrame, bool aHasDisplayItem, bool aRebuildDisplayItems)
6972 721 : {
6973 : if (aHasDisplayItem) {
6974 721 : aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT);
6975 : }
6976 :
6977 : if (aRebuildDisplayItems) {
6978 0 : aFrame->MarkNeedsDisplayItemRebuild();
6979 0 : }
6980 : SVGObserverUtils::InvalidateDirectRenderingObservers(aFrame);
6981 0 : bool needsSchedulePaint = false;
6982 721 : if (nsLayoutUtils::IsPopup(aFrame)) {
6983 0 : needsSchedulePaint = true;
6984 : } else {
6985 : nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
6986 0 : while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
6987 2125 : if (aHasDisplayItem && !parent->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) {
6988 0 : parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
6989 : }
6990 : SVGObserverUtils::InvalidateDirectRenderingObservers(parent);
6991 0 :
6992 : // If we're inside a popup, then we need to make sure that we
6993 : // call schedule paint so that the NS_FRAME_UPDATE_LAYER_TREE
6994 : // flag gets added to the popup display root frame.
6995 : if (nsLayoutUtils::IsPopup(parent)) {
6996 280 : needsSchedulePaint = true;
6997 : break;
6998 : }
6999 : parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
7000 280 : }
7001 : if (!parent) {
7002 686 : needsSchedulePaint = true;
7003 87 : }
7004 : }
7005 : if (!aHasDisplayItem) {
7006 721 : return;
7007 : }
7008 : if (needsSchedulePaint) {
7009 0 : nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
7010 122 : SchedulePaintInternal(displayRoot, aFrame);
7011 122 : }
7012 : if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
7013 0 : aFrame->DeleteProperty(nsIFrame::InvalidationRect());
7014 0 : aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT);
7015 : }
7016 : }
7017 :
7018 : void
7019 : nsIFrame::InvalidateFrameSubtree(bool aRebuildDisplayItems /* = true */)
7020 618 : {
7021 : InvalidateFrame(0, aRebuildDisplayItems);
7022 618 :
7023 : if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) {
7024 1236 : return;
7025 0 : }
7026 :
7027 : AddStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
7028 387 :
7029 : AutoTArray<nsIFrame::ChildList,4> childListArray;
7030 774 : GetCrossDocChildLists(&childListArray);
7031 387 :
7032 : nsIFrame::ChildListArrayIterator lists(childListArray);
7033 : for (; !lists.IsDone(); lists.Next()) {
7034 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
7035 476 : for (; !childFrames.AtEnd(); childFrames.Next()) {
7036 0 : // Don't explicitly rebuild display items for our descendants,
7037 : // since we should be marked and it implicitly includes all
7038 : // descendants.
7039 : childFrames.get()->InvalidateFrameSubtree(false);
7040 0 : }
7041 : }
7042 : }
7043 :
7044 : void
7045 : nsIFrame::ClearInvalidationStateBits()
7046 396 : {
7047 : if (HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
7048 0 : AutoTArray<nsIFrame::ChildList,4> childListArray;
7049 0 : GetCrossDocChildLists(&childListArray);
7050 0 :
7051 : nsIFrame::ChildListArrayIterator lists(childListArray);
7052 : for (; !lists.IsDone(); lists.Next()) {
7053 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
7054 456 : for (; !childFrames.AtEnd(); childFrames.Next()) {
7055 982 : childFrames.get()->ClearInvalidationStateBits();
7056 377 : }
7057 : }
7058 : }
7059 :
7060 : RemoveStateBits(NS_FRAME_NEEDS_PAINT |
7061 396 : NS_FRAME_DESCENDANT_NEEDS_PAINT |
7062 : NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
7063 396 : }
7064 0 :
7065 : void
7066 : nsIFrame::InvalidateFrame(uint32_t aDisplayItemKey, bool aRebuildDisplayItems /* = true */)
7067 721 : {
7068 : bool hasDisplayItem =
7069 : !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
7070 721 : InvalidateFrameInternal(this, hasDisplayItem, aRebuildDisplayItems);
7071 0 : }
7072 0 :
7073 : void
7074 : nsIFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey, bool aRebuildDisplayItems /* = true */)
7075 0 : {
7076 : if (aRect.IsEmpty()) {
7077 0 : return;
7078 : }
7079 : bool hasDisplayItem =
7080 : !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
7081 0 : bool alreadyInvalid = false;
7082 0 : if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
7083 0 : InvalidateFrameInternal(this, hasDisplayItem, aRebuildDisplayItems);
7084 0 : } else {
7085 : alreadyInvalid = true;
7086 : }
7087 :
7088 : if (!hasDisplayItem) {
7089 0 : return;
7090 : }
7091 :
7092 : nsRect* rect;
7093 : if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
7094 0 : rect = GetProperty(InvalidationRect());
7095 0 : MOZ_ASSERT(rect);
7096 0 : } else {
7097 : if (alreadyInvalid) {
7098 0 : return;
7099 : }
7100 : rect = new nsRect();
7101 0 : AddProperty(InvalidationRect(), rect);
7102 0 : AddStateBits(NS_FRAME_HAS_INVALID_RECT);
7103 : }
7104 :
7105 : *rect = rect->Union(aRect);
7106 0 : }
7107 :
7108 : /*static*/ uint8_t nsIFrame::sLayerIsPrerenderedDataKey;
7109 :
7110 : static bool
7111 : DoesLayerHaveOutOfDateFrameMetrics(Layer* aLayer)
7112 0 : {
7113 : for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
7114 0 : const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
7115 0 : if (!metrics.IsScrollable()) {
7116 0 : continue;
7117 0 : }
7118 : nsIScrollableFrame* scrollableFrame =
7119 : nsLayoutUtils::FindScrollableFrameFor(metrics.GetScrollId());
7120 0 : if (!scrollableFrame) {
7121 0 : // This shouldn't happen, so let's do the safe thing and trigger a full
7122 : // paint if it does.
7123 : return true;
7124 0 : }
7125 : nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
7126 0 : if (metrics.GetScrollOffset() != CSSPoint::FromAppUnits(scrollPosition)) {
7127 0 : return true;
7128 : }
7129 : }
7130 : return false;
7131 : }
7132 :
7133 : static bool
7134 : DoesLayerOrAncestorsHaveOutOfDateFrameMetrics(Layer* aLayer)
7135 0 : {
7136 : for (Layer* layer = aLayer; layer; layer = layer->GetParent()) {
7137 0 : if (DoesLayerHaveOutOfDateFrameMetrics(layer)) {
7138 0 : return true;
7139 : }
7140 : }
7141 : return false;
7142 : }
7143 :
7144 : bool
7145 : nsIFrame::TryUpdateTransformOnly(Layer** aLayerResult)
7146 0 : {
7147 : Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
7148 : this, DisplayItemType::TYPE_TRANSFORM);
7149 0 : if (!layer || !layer->HasUserData(LayerIsPrerenderedDataKey())) {
7150 0 : // If this layer isn't prerendered or we clip composites to our OS
7151 : // window, then we can't correctly optimize to an empty
7152 : // transaction in general.
7153 : return false;
7154 : }
7155 :
7156 : if (DoesLayerOrAncestorsHaveOutOfDateFrameMetrics(layer)) {
7157 0 : // At least one scroll frame that can affect the position of this layer
7158 : // has changed its scroll offset since the last paint. Schedule a full
7159 : // paint to make sure that this layer's transform and all the frame
7160 : // metrics that affect it are in sync.
7161 : return false;
7162 : }
7163 :
7164 : gfx::Matrix4x4Flagged transform3d;
7165 0 : if (!nsLayoutUtils::GetLayerTransformForFrame(this, &transform3d)) {
7166 0 : // We're not able to compute a layer transform that we know would
7167 : // be used at the next layers transaction, so we can't only update
7168 : // the transform and will need to schedule an invalidating paint.
7169 : return false;
7170 : }
7171 : gfx::Matrix transform;
7172 0 : gfx::Matrix previousTransform;
7173 0 : // FIXME/bug 796690 and 796705: in general, changes to 3D
7174 : // transforms, or transform changes to properties other than
7175 : // translation, may lead us to choose a different rendering
7176 : // resolution for our layer. So if the transform is 3D or has a
7177 : // non-translation change, bail and schedule an invalidating paint.
7178 : // (We can often do better than this, for example for scale-down
7179 : // changes.)
7180 : static const gfx::Float kError = 0.0001f;
7181 : if (!transform3d.Is2D(&transform) ||
7182 0 : !layer->GetBaseTransform().Is2D(&previousTransform) ||
7183 0 : !gfx::FuzzyEqual(transform._11, previousTransform._11, kError) ||
7184 0 : !gfx::FuzzyEqual(transform._22, previousTransform._22, kError) ||
7185 0 : !gfx::FuzzyEqual(transform._21, previousTransform._21, kError) ||
7186 0 : !gfx::FuzzyEqual(transform._12, previousTransform._12, kError)) {
7187 0 : return false;
7188 : }
7189 : layer->SetBaseTransformForNextTransaction(transform3d.GetMatrix());
7190 0 : *aLayerResult = layer;
7191 0 : return true;
7192 0 : }
7193 :
7194 : bool
7195 : nsIFrame::IsInvalid(nsRect& aRect)
7196 253 : {
7197 : if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
7198 506 : return false;
7199 : }
7200 :
7201 : if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
7202 40 : nsRect* rect = GetProperty(InvalidationRect());
7203 0 : NS_ASSERTION(rect, "Must have an invalid rect if NS_FRAME_HAS_INVALID_RECT is set!");
7204 0 : aRect = *rect;
7205 0 : } else {
7206 : aRect.SetEmpty();
7207 20 : }
7208 : return true;
7209 : }
7210 :
7211 : void
7212 : nsIFrame::SchedulePaint(PaintType aType, bool aFrameChanged)
7213 96 : {
7214 : nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
7215 96 : InvalidateRenderingObservers(displayRoot, this, aFrameChanged);
7216 96 : SchedulePaintInternal(displayRoot, this, aType);
7217 96 : }
7218 96 :
7219 : void
7220 : nsIFrame::SchedulePaintWithoutInvalidatingObservers(PaintType aType)
7221 2 : {
7222 : nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
7223 2 : SchedulePaintInternal(displayRoot, this, aType);
7224 2 : }
7225 2 :
7226 : Layer*
7227 : nsIFrame::InvalidateLayer(DisplayItemType aDisplayItemKey,
7228 0 : const nsIntRect* aDamageRect,
7229 : const nsRect* aFrameDamageRect,
7230 : uint32_t aFlags /* = 0 */)
7231 : {
7232 : NS_ASSERTION(aDisplayItemKey > DisplayItemType::TYPE_ZERO, "Need a key");
7233 20 :
7234 : Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
7235 0 :
7236 : nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(this);
7237 20 : InvalidateRenderingObservers(displayRoot, this);
7238 20 :
7239 : // Check if frame supports WebRender's async update
7240 : if ((aFlags & UPDATE_IS_ASYNC) &&
7241 20 : WebRenderUserData::SupportsAsyncUpdate(this)) {
7242 0 : // WebRender does not use layer, then return nullptr.
7243 : return nullptr;
7244 : }
7245 :
7246 : // If the layer is being updated asynchronously, and it's being forwarded
7247 : // to a compositor, then we don't need to invalidate.
7248 : if ((aFlags & UPDATE_IS_ASYNC) && layer && layer->SupportsAsyncUpdate()) {
7249 0 : return layer;
7250 : }
7251 :
7252 : if (!layer) {
7253 0 : if (aFrameDamageRect && aFrameDamageRect->IsEmpty()) {
7254 0 : return nullptr;
7255 : }
7256 :
7257 : // Plugins can transition from not rendering anything to rendering,
7258 : // and still only call this. So always invalidate, with specifying
7259 : // the display item type just in case.
7260 : //
7261 : // In the bug 930056, dialer app startup but not shown on the
7262 : // screen because sometimes we don't have any retainned data
7263 : // for remote type displayitem and thus Repaint event is not
7264 : // triggered. So, always invalidate here as well.
7265 : DisplayItemType displayItemKey = aDisplayItemKey;
7266 0 : if (aDisplayItemKey == DisplayItemType::TYPE_PLUGIN ||
7267 0 : aDisplayItemKey == DisplayItemType::TYPE_REMOTE) {
7268 20 : displayItemKey = DisplayItemType::TYPE_ZERO;
7269 0 : }
7270 :
7271 : if (aFrameDamageRect) {
7272 20 : InvalidateFrameWithRect(*aFrameDamageRect, static_cast<uint32_t>(displayItemKey));
7273 0 : } else {
7274 : InvalidateFrame(static_cast<uint32_t>(displayItemKey));
7275 0 : }
7276 :
7277 : return nullptr;
7278 : }
7279 :
7280 : if (aDamageRect && aDamageRect->IsEmpty()) {
7281 0 : return layer;
7282 : }
7283 :
7284 : if (aDamageRect) {
7285 0 : layer->AddInvalidRect(*aDamageRect);
7286 : } else {
7287 : layer->SetInvalidRectToVisibleRegion();
7288 0 : }
7289 :
7290 : SchedulePaintInternal(displayRoot, this, PAINT_COMPOSITE_ONLY);
7291 0 : return layer;
7292 0 : }
7293 :
7294 : static nsRect
7295 : ComputeEffectsRect(nsIFrame* aFrame, const nsRect& aOverflowRect,
7296 720 : const nsSize& aNewSize)
7297 : {
7298 : nsRect r = aOverflowRect;
7299 0 :
7300 : if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
7301 1440 : // For SVG frames, we only need to account for filters.
7302 : // TODO: We could also take account of clipPath and mask to reduce the
7303 : // visual overflow, but that's not essential.
7304 : if (aFrame->StyleEffects()->HasFilters()) {
7305 104 : aFrame->SetProperty
7306 : (nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
7307 0 : r = nsSVGUtils::GetPostFilterVisualOverflowRect(aFrame, aOverflowRect);
7308 0 : }
7309 : return r;
7310 : }
7311 :
7312 : // box-shadow
7313 : r.UnionRect(r, nsLayoutUtils::GetBoxShadowRectForFrame(aFrame, aNewSize));
7314 668 :
7315 : // border-image-outset.
7316 : // We need to include border-image-outset because it can cause the
7317 : // border image to be drawn beyond the border box.
7318 :
7319 : // (1) It's important we not check whether there's a border-image
7320 : // since the style hint for a change in border image doesn't cause
7321 : // reflow, and that's probably more important than optimizing the
7322 : // overflow areas for the silly case of border-image-outset without
7323 : // border-image
7324 : // (2) It's important that we not check whether the border-image
7325 : // is actually loaded, since that would require us to reflow when
7326 : // the image loads.
7327 : const nsStyleBorder* styleBorder = aFrame->StyleBorder();
7328 0 : nsMargin outsetMargin = styleBorder->GetImageOutset();
7329 0 :
7330 : if (outsetMargin != nsMargin(0, 0, 0, 0)) {
7331 0 : nsRect outsetRect(nsPoint(0, 0), aNewSize);
7332 0 : outsetRect.Inflate(outsetMargin);
7333 0 : r.UnionRect(r, outsetRect);
7334 0 : }
7335 :
7336 : // Note that we don't remove the outlineInnerRect if a frame loses outline
7337 : // style. That would require an extra property lookup for every frame,
7338 : // or a new frame state bit to track whether a property had been stored,
7339 : // or something like that. It's not worth doing that here. At most it's
7340 : // only one heap-allocated rect per frame and it will be cleaned up when
7341 : // the frame dies.
7342 :
7343 : if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
7344 668 : aFrame->SetProperty
7345 : (nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
7346 0 : r = nsSVGIntegrationUtils::ComputePostEffectsVisualOverflowRect(aFrame, r);
7347 0 : }
7348 :
7349 : return r;
7350 : }
7351 :
7352 : void
7353 : nsIFrame::MovePositionBy(const nsPoint& aTranslation)
7354 0 : {
7355 : nsPoint position = GetNormalPosition() + aTranslation;
7356 0 :
7357 : const nsMargin* computedOffsets = nullptr;
7358 0 : if (IsRelativelyPositioned()) {
7359 0 : computedOffsets = GetProperty(nsIFrame::ComputedOffsetProperty());
7360 0 : }
7361 : ReflowInput::ApplyRelativePositioning(this, computedOffsets ?
7362 0 : *computedOffsets : nsMargin(),
7363 : &position);
7364 0 : SetPosition(position);
7365 0 : }
7366 0 :
7367 : nsRect
7368 : nsIFrame::GetNormalRect() const
7369 0 : {
7370 : // It might be faster to first check
7371 : // StyleDisplay()->IsRelativelyPositionedStyle().
7372 : nsPoint* normalPosition = GetProperty(NormalPositionProperty());
7373 4 : if (normalPosition) {
7374 2 : return nsRect(*normalPosition, GetSize());
7375 0 : }
7376 : return GetRect();
7377 : }
7378 :
7379 : nsPoint
7380 : nsIFrame::GetPositionIgnoringScrolling() const
7381 118 : {
7382 : return GetParent() ? GetParent()->GetPositionOfChildIgnoringScrolling(this)
7383 354 : : GetPosition();
7384 472 : }
7385 :
7386 : nsRect
7387 : nsIFrame::GetOverflowRect(nsOverflowType aType) const
7388 2060 : {
7389 : MOZ_ASSERT(aType == eVisualOverflow || aType == eScrollableOverflow,
7390 0 : "unexpected type");
7391 :
7392 : // Note that in some cases the overflow area might not have been
7393 : // updated (yet) to reflect any outline set on the frame or the area
7394 : // of child frames. That's OK because any reflow that updates these
7395 : // areas will invalidate the appropriate area, so any (mis)uses of
7396 : // this method will be fixed up.
7397 :
7398 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
7399 2060 : // there is an overflow rect, and it's not stored as deltas but as
7400 : // a separately-allocated rect
7401 : return GetOverflowAreasProperty()->Overflow(aType);
7402 185 : }
7403 :
7404 : if (aType == eVisualOverflow &&
7405 1875 : mOverflow.mType != NS_FRAME_OVERFLOW_NONE) {
7406 : return GetVisualOverflowFromDeltas();
7407 0 : }
7408 :
7409 : return nsRect(nsPoint(0, 0), GetSize());
7410 3750 : }
7411 :
7412 : nsOverflowAreas
7413 : nsIFrame::GetOverflowAreas() const
7414 513 : {
7415 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
7416 0 : // there is an overflow rect, and it's not stored as deltas but as
7417 : // a separately-allocated rect
7418 : return *GetOverflowAreasProperty();
7419 20 : }
7420 :
7421 : return nsOverflowAreas(GetVisualOverflowFromDeltas(),
7422 0 : nsRect(nsPoint(0, 0), GetSize()));
7423 1972 : }
7424 :
7425 : nsOverflowAreas
7426 : nsIFrame::GetOverflowAreasRelativeToSelf() const
7427 0 : {
7428 : if (IsTransformed()) {
7429 0 : nsOverflowAreas* preTransformOverflows =
7430 : GetProperty(PreTransformOverflowAreasProperty());
7431 0 : if (preTransformOverflows) {
7432 0 : return nsOverflowAreas(preTransformOverflows->VisualOverflow(),
7433 0 : preTransformOverflows->ScrollableOverflow());
7434 0 : }
7435 : }
7436 : return nsOverflowAreas(GetVisualOverflowRect(),
7437 0 : GetScrollableOverflowRect());
7438 0 : }
7439 :
7440 : nsRect
7441 : nsIFrame::GetScrollableOverflowRectRelativeToParent() const
7442 96 : {
7443 : return GetScrollableOverflowRect() + mRect.TopLeft();
7444 192 : }
7445 :
7446 : nsRect
7447 : nsIFrame::GetVisualOverflowRectRelativeToParent() const
7448 0 : {
7449 : return GetVisualOverflowRect() + mRect.TopLeft();
7450 0 : }
7451 :
7452 : nsRect
7453 : nsIFrame::GetScrollableOverflowRectRelativeToSelf() const
7454 0 : {
7455 : if (IsTransformed()) {
7456 0 : nsOverflowAreas* preTransformOverflows =
7457 : GetProperty(PreTransformOverflowAreasProperty());
7458 0 : if (preTransformOverflows)
7459 0 : return preTransformOverflows->ScrollableOverflow();
7460 0 : }
7461 : return GetScrollableOverflowRect();
7462 0 : }
7463 :
7464 : nsRect
7465 : nsIFrame::GetVisualOverflowRectRelativeToSelf() const
7466 73 : {
7467 : if (IsTransformed()) {
7468 73 : nsOverflowAreas* preTransformOverflows =
7469 : GetProperty(PreTransformOverflowAreasProperty());
7470 22 : if (preTransformOverflows)
7471 11 : return preTransformOverflows->VisualOverflow();
7472 0 : }
7473 : return GetVisualOverflowRect();
7474 62 : }
7475 :
7476 : nsRect
7477 : nsIFrame::GetPreEffectsVisualOverflowRect() const
7478 0 : {
7479 : nsRect* r = GetProperty(nsIFrame::PreEffectsBBoxProperty());
7480 0 : return r ? *r : GetVisualOverflowRectRelativeToSelf();
7481 0 : }
7482 :
7483 : bool
7484 : nsIFrame::UpdateOverflow()
7485 0 : {
7486 : MOZ_ASSERT(FrameMaintainsOverflow(),
7487 0 : "Non-display SVG do not maintain visual overflow rects");
7488 :
7489 : nsRect rect(nsPoint(0, 0), GetSize());
7490 0 : nsOverflowAreas overflowAreas(rect, rect);
7491 0 :
7492 : if (!ComputeCustomOverflow(overflowAreas)) {
7493 0 : return false;
7494 : }
7495 :
7496 : UnionChildOverflow(overflowAreas);
7497 0 :
7498 : if (FinishAndStoreOverflow(overflowAreas, GetSize())) {
7499 0 : nsView* view = GetView();
7500 0 : if (view) {
7501 0 : uint32_t flags = GetXULLayoutFlags();
7502 0 :
7503 : if ((flags & NS_FRAME_NO_SIZE_VIEW) == 0) {
7504 0 : // Make sure the frame's view is properly sized.
7505 : nsViewManager* vm = view->GetViewManager();
7506 0 : vm->ResizeView(view, overflowAreas.VisualOverflow(), true);
7507 0 : }
7508 : }
7509 :
7510 : return true;
7511 : }
7512 :
7513 : return false;
7514 : }
7515 :
7516 : /* virtual */ bool
7517 : nsFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas)
7518 0 : {
7519 : return true;
7520 0 : }
7521 :
7522 : /* virtual */ void
7523 : nsFrame::UnionChildOverflow(nsOverflowAreas& aOverflowAreas)
7524 0 : {
7525 : if (!DoesClipChildren() &&
7526 0 : !(IsXULCollapsed() && (IsXULBoxFrame() || ::IsXULBoxWrapped(this)))) {
7527 0 : nsLayoutUtils::UnionChildOverflow(this, aOverflowAreas);
7528 0 : }
7529 : }
7530 0 :
7531 :
7532 : // Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
7533 : // 4 for the frames above the document's frames:
7534 : // the Viewport, GFXScroll, ScrollPort, and Canvas
7535 : #define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4)
7536 :
7537 : bool
7538 : nsFrame::IsFrameTreeTooDeep(const ReflowInput& aReflowInput,
7539 49 : ReflowOutput& aMetrics,
7540 : nsReflowStatus& aStatus)
7541 : {
7542 : if (aReflowInput.mReflowDepth > MAX_FRAME_DEPTH) {
7543 0 : NS_WARNING("frame tree too deep; setting zero size and returning");
7544 0 : AddStateBits(NS_FRAME_TOO_DEEP_IN_FRAME_TREE);
7545 0 : ClearOverflowRects();
7546 0 : aMetrics.ClearSize();
7547 0 : aMetrics.SetBlockStartAscent(0);
7548 0 : aMetrics.mCarriedOutBEndMargin.Zero();
7549 0 : aMetrics.mOverflowAreas.Clear();
7550 0 :
7551 : aStatus.Reset();
7552 0 : if (GetNextInFlow()) {
7553 0 : // Reflow depth might vary between reflows, so we might have
7554 : // successfully reflowed and split this frame before. If so, we
7555 : // shouldn't delete its continuations.
7556 : aStatus.SetIncomplete();
7557 : }
7558 :
7559 : return true;
7560 : }
7561 : RemoveStateBits(NS_FRAME_TOO_DEEP_IN_FRAME_TREE);
7562 0 : return false;
7563 0 : }
7564 :
7565 : bool
7566 : nsIFrame::IsBlockWrapper() const
7567 693 : {
7568 : nsAtom *pseudoType = Style()->GetPseudo();
7569 0 : return (pseudoType == nsCSSAnonBoxes::mozBlockInsideInlineWrapper ||
7570 1386 : pseudoType == nsCSSAnonBoxes::buttonContent ||
7571 1386 : pseudoType == nsCSSAnonBoxes::cellContent);
7572 1386 : }
7573 :
7574 : static nsIFrame*
7575 : GetNearestBlockContainer(nsIFrame* frame)
7576 314 : {
7577 : // The block wrappers we use to wrap blocks inside inlines aren't
7578 : // described in the CSS spec. We need to make them not be containing
7579 : // blocks.
7580 : // Since the parent of such a block is either a normal block or
7581 : // another such pseudo, this shouldn't cause anything bad to happen.
7582 : // Also the anonymous blocks inside table cells are not containing blocks.
7583 : //
7584 : // If we ever start skipping table row groups from being containing blocks,
7585 : // you need to remove the StickyScrollContainer hack referencing bug 1421660.
7586 : while (frame->IsFrameOfType(nsIFrame::eLineParticipant) ||
7587 942 : frame->IsBlockWrapper() ||
7588 0 : // Table rows are not containing blocks either
7589 : frame->IsTableRowFrame()) {
7590 0 : frame = frame->GetParent();
7591 0 : NS_ASSERTION(frame, "How come we got to the root frame without seeing a containing block?");
7592 0 : }
7593 : return frame;
7594 314 : }
7595 :
7596 : nsIFrame*
7597 : nsIFrame::GetContainingBlock(uint32_t aFlags,
7598 331 : const nsStyleDisplay* aStyleDisplay) const
7599 : {
7600 : MOZ_ASSERT(aStyleDisplay == StyleDisplay());
7601 0 : if (!GetParent()) {
7602 331 : return nullptr;
7603 : }
7604 : // MathML frames might have absolute positioning style, but they would
7605 : // still be in-flow. So we have to check to make sure that the frame
7606 : // is really out-of-flow too.
7607 : nsIFrame* f;
7608 : if (IsAbsolutelyPositioned(aStyleDisplay) &&
7609 0 : (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
7610 0 : f = GetParent(); // the parent is always the containing block
7611 0 : } else {
7612 : f = GetNearestBlockContainer(GetParent());
7613 314 : }
7614 :
7615 : if (aFlags & SKIP_SCROLLED_FRAME && f &&
7616 481 : f->Style()->GetPseudo() == nsCSSAnonBoxes::scrolledContent) {
7617 300 : f = f->GetParent();
7618 8 : }
7619 : return f;
7620 : }
7621 :
7622 : #ifdef DEBUG_FRAME_DUMP
7623 :
7624 : int32_t nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
7625 0 : {
7626 : int32_t result = -1;
7627 0 :
7628 : nsIContent* content = aFrame->GetContent();
7629 0 : if (content) {
7630 0 : nsIContent* parentContent = content->GetParent();
7631 0 : if (parentContent) {
7632 0 : result = parentContent->ComputeIndexOf(content);
7633 0 : }
7634 : }
7635 :
7636 : return result;
7637 0 : }
7638 :
7639 : /**
7640 : * List a frame tree to stderr. Meant to be called from gdb.
7641 : */
7642 : void
7643 : DebugListFrameTree(nsIFrame* aFrame)
7644 0 : {
7645 : ((nsFrame*)aFrame)->List(stderr);
7646 0 : }
7647 0 :
7648 : void
7649 : nsIFrame::ListTag(nsACString& aTo) const
7650 0 : {
7651 : ListTag(aTo, this);
7652 0 : }
7653 0 :
7654 : /* static */
7655 : void
7656 : nsIFrame::ListTag(nsACString& aTo, const nsIFrame* aFrame) {
7657 0 : nsAutoString tmp;
7658 0 : aFrame->GetFrameName(tmp);
7659 0 : aTo += NS_ConvertUTF16toUTF8(tmp).get();
7660 0 : aTo += nsPrintfCString("@%p", static_cast<const void*>(aFrame));
7661 0 : }
7662 0 :
7663 : // Debugging
7664 : void
7665 : nsIFrame::ListGeneric(nsACString& aTo, const char* aPrefix, uint32_t aFlags) const
7666 0 : {
7667 : aTo += aPrefix;
7668 0 : ListTag(aTo);
7669 0 : if (HasView()) {
7670 0 : aTo += nsPrintfCString(" [view=%p]", static_cast<void*>(GetView()));
7671 0 : }
7672 : if (GetParent()) {
7673 0 : aTo += nsPrintfCString(" parent=%p", static_cast<void*>(GetParent()));
7674 0 : }
7675 : if (GetNextSibling()) {
7676 0 : aTo += nsPrintfCString(" next=%p", static_cast<void*>(GetNextSibling()));
7677 0 : }
7678 : if (GetPrevContinuation()) {
7679 0 : bool fluid = GetPrevInFlow() == GetPrevContinuation();
7680 0 : aTo += nsPrintfCString(" prev-%s=%p", fluid?"in-flow":"continuation",
7681 0 : static_cast<void*>(GetPrevContinuation()));
7682 0 : }
7683 : if (GetNextContinuation()) {
7684 0 : bool fluid = GetNextInFlow() == GetNextContinuation();
7685 0 : aTo += nsPrintfCString(" next-%s=%p", fluid?"in-flow":"continuation",
7686 0 : static_cast<void*>(GetNextContinuation()));
7687 0 : }
7688 : void* IBsibling = GetProperty(IBSplitSibling());
7689 0 : if (IBsibling) {
7690 0 : aTo += nsPrintfCString(" IBSplitSibling=%p", IBsibling);
7691 0 : }
7692 : void* IBprevsibling = GetProperty(IBSplitPrevSibling());
7693 0 : if (IBprevsibling) {
7694 0 : aTo += nsPrintfCString(" IBSplitPrevSibling=%p", IBprevsibling);
7695 0 : }
7696 : aTo += nsPrintfCString(" {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
7697 0 :
7698 : mozilla::WritingMode wm = GetWritingMode();
7699 0 : if (wm.IsVertical() || !wm.IsBidiLTR()) {
7700 0 : aTo += nsPrintfCString(" wm=%s: logical size={%d,%d}", wm.DebugString(),
7701 0 : ISize(), BSize());
7702 0 : }
7703 :
7704 : nsIFrame* parent = GetParent();
7705 0 : if (parent) {
7706 0 : WritingMode pWM = parent->GetWritingMode();
7707 0 : if (pWM.IsVertical() || !pWM.IsBidiLTR()) {
7708 0 : nsSize containerSize = parent->mRect.Size();
7709 0 : LogicalRect lr(pWM, mRect, containerSize);
7710 0 : aTo += nsPrintfCString(" parent wm=%s, cs={%d,%d}, "
7711 0 : " logicalRect={%d,%d,%d,%d}",
7712 : pWM.DebugString(),
7713 : containerSize.width, containerSize.height,
7714 : lr.IStart(pWM), lr.BStart(pWM),
7715 0 : lr.ISize(pWM), lr.BSize(pWM));
7716 0 : }
7717 : }
7718 : nsIFrame* f = const_cast<nsIFrame*>(this);
7719 0 : if (f->HasOverflowAreas()) {
7720 0 : nsRect vo = f->GetVisualOverflowRect();
7721 0 : if (!vo.IsEqualEdges(mRect)) {
7722 0 : aTo += nsPrintfCString(" vis-overflow=%d,%d,%d,%d", vo.x, vo.y, vo.width, vo.height);
7723 0 : }
7724 : nsRect so = f->GetScrollableOverflowRect();
7725 0 : if (!so.IsEqualEdges(mRect)) {
7726 0 : aTo += nsPrintfCString(" scr-overflow=%d,%d,%d,%d", so.x, so.y, so.width, so.height);
7727 0 : }
7728 : }
7729 : if (0 != mState) {
7730 0 : aTo += nsPrintfCString(" [state=%016llx]", (unsigned long long)mState);
7731 0 : }
7732 : if (HasProperty(BidiDataProperty())) {
7733 0 : FrameBidiData bidi = GetBidiData();
7734 0 : aTo += nsPrintfCString(" bidi(%d,%d,%d)", bidi.baseLevel,
7735 0 : bidi.embeddingLevel, bidi.precedingControl);
7736 0 : }
7737 : if (IsTransformed()) {
7738 0 : aTo += nsPrintfCString(" transformed");
7739 0 : }
7740 : if (ChildrenHavePerspective()) {
7741 0 : aTo += nsPrintfCString(" perspective");
7742 0 : }
7743 : if (Extend3DContext()) {
7744 0 : aTo += nsPrintfCString(" extend-3d");
7745 0 : }
7746 : if (Combines3DTransformWithAncestors()) {
7747 0 : aTo += nsPrintfCString(" combines-3d-transform-with-ancestors");
7748 0 : }
7749 : if (mContent) {
7750 0 : aTo += nsPrintfCString(" [content=%p]", static_cast<void*>(mContent));
7751 0 : }
7752 : aTo += nsPrintfCString(" [sc=%p", static_cast<void*>(mComputedStyle));
7753 0 : if (mComputedStyle) {
7754 0 : nsAtom* pseudoTag = mComputedStyle->GetPseudo();
7755 0 : if (pseudoTag) {
7756 0 : nsAutoString atomString;
7757 0 : pseudoTag->ToString(atomString);
7758 0 : aTo += nsPrintfCString("%s", NS_LossyConvertUTF16toASCII(atomString).get());
7759 0 : }
7760 : }
7761 : aTo += "]";
7762 0 : }
7763 0 :
7764 : void
7765 : nsIFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
7766 0 : {
7767 : nsCString str;
7768 0 : ListGeneric(str, aPrefix, aFlags);
7769 0 : fprintf_stderr(out, "%s\n", str.get());
7770 0 : }
7771 0 :
7772 : nsresult
7773 : nsFrame::GetFrameName(nsAString& aResult) const
7774 0 : {
7775 : return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult);
7776 0 : }
7777 :
7778 : nsresult
7779 : nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
7780 0 : {
7781 : aResult = aType;
7782 0 : if (mContent && !mContent->IsText()) {
7783 0 : nsAutoString buf;
7784 0 : mContent->NodeInfo()->NameAtom()->ToString(buf);
7785 0 : if (IsSubDocumentFrame()) {
7786 0 : nsAutoString src;
7787 0 : mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
7788 0 : buf.AppendLiteral(" src=");
7789 0 : buf.Append(src);
7790 0 : }
7791 : aResult.Append('(');
7792 0 : aResult.Append(buf);
7793 0 : aResult.Append(')');
7794 0 : }
7795 : aResult.Append('(');
7796 0 : aResult.AppendInt(ContentIndexInContainer(this));
7797 0 : aResult.Append(')');
7798 0 : return NS_OK;
7799 0 : }
7800 :
7801 : void
7802 : nsIFrame::DumpFrameTree() const
7803 0 : {
7804 : RootFrameList(PresContext(), stderr);
7805 0 : }
7806 0 :
7807 : void
7808 : nsIFrame::DumpFrameTreeLimited() const
7809 0 : {
7810 : List(stderr);
7811 0 : }
7812 0 :
7813 : void
7814 : nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, const char* aPrefix)
7815 0 : {
7816 : if (!aPresContext || !out)
7817 0 : return;
7818 :
7819 : nsIPresShell *shell = aPresContext->GetPresShell();
7820 0 : if (shell) {
7821 0 : nsIFrame* frame = shell->GetRootFrame();
7822 0 : if(frame) {
7823 0 : frame->List(out, aPrefix);
7824 0 : }
7825 : }
7826 : }
7827 : #endif
7828 :
7829 : bool
7830 : nsIFrame::IsVisibleForPainting(nsDisplayListBuilder* aBuilder) {
7831 1 : if (!StyleVisibility()->IsVisible())
7832 1 : return false;
7833 : Selection* sel = aBuilder->GetBoundingSelection();
7834 834 : return !sel || IsVisibleInSelection(sel);
7835 834 : }
7836 :
7837 : bool
7838 : nsIFrame::IsVisibleForPainting() {
7839 0 : if (!StyleVisibility()->IsVisible())
7840 0 : return false;
7841 :
7842 : nsPresContext* pc = PresContext();
7843 0 : if (!pc->IsRenderingOnlySelection())
7844 0 : return true;
7845 :
7846 : nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(pc->PresShell()));
7847 0 : if (selcon) {
7848 0 : RefPtr<Selection> sel =
7849 : selcon->GetSelection(nsISelectionController::SELECTION_NORMAL);
7850 0 : if (sel) {
7851 0 : return IsVisibleInSelection(sel);
7852 0 : }
7853 : }
7854 : return true;
7855 : }
7856 :
7857 : bool
7858 : nsIFrame::IsVisibleInSelection(nsDisplayListBuilder* aBuilder) {
7859 0 : Selection* sel = aBuilder->GetBoundingSelection();
7860 0 : return !sel || IsVisibleInSelection(sel);
7861 0 : }
7862 :
7863 : bool
7864 : nsIFrame::IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder) {
7865 0 : if (!StyleVisibility()->IsVisibleOrCollapsed())
7866 0 : return false;
7867 : Selection* sel = aBuilder->GetBoundingSelection();
7868 0 : return !sel || IsVisibleInSelection(sel);
7869 0 : }
7870 :
7871 : bool
7872 : nsIFrame::IsVisibleInSelection(Selection* aSelection)
7873 0 : {
7874 : if (!GetContent() || !GetContent()->IsSelectionDescendant()) {
7875 0 : return false;
7876 : }
7877 :
7878 : ErrorResult rv;
7879 0 : bool vis = aSelection->ContainsNode(*mContent, true, rv);
7880 0 : return rv.Failed() || vis;
7881 0 : }
7882 :
7883 : /* virtual */ bool
7884 : nsFrame::IsEmpty()
7885 1 : {
7886 : return false;
7887 29 : }
7888 :
7889 : bool
7890 : nsIFrame::CachedIsEmpty()
7891 23 : {
7892 : MOZ_ASSERT(!(GetStateBits() & NS_FRAME_IS_DIRTY),
7893 0 : "Must only be called on reflowed lines");
7894 : return IsEmpty();
7895 23 : }
7896 :
7897 : /* virtual */ bool
7898 : nsFrame::IsSelfEmpty()
7899 0 : {
7900 : return false;
7901 0 : }
7902 :
7903 : nsresult
7904 : nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon)
7905 1 : {
7906 : if (!aPresContext || !aSelCon)
7907 3 : return NS_ERROR_INVALID_ARG;
7908 :
7909 : nsIFrame *frame = this;
7910 1 : while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
7911 6 : nsITextControlFrame *tcf = do_QueryFrame(frame);
7912 1 : if (tcf) {
7913 1 : return tcf->GetOwnedSelectionController(aSelCon);
7914 1 : }
7915 : frame = frame->GetParent();
7916 0 : }
7917 :
7918 : return CallQueryInterface(aPresContext->GetPresShell(), aSelCon);
7919 0 : }
7920 :
7921 : already_AddRefed<nsFrameSelection>
7922 : nsIFrame::GetFrameSelection()
7923 0 : {
7924 : RefPtr<nsFrameSelection> fs =
7925 : const_cast<nsFrameSelection*>(GetConstFrameSelection());
7926 0 : return fs.forget();
7927 0 : }
7928 :
7929 : const nsFrameSelection*
7930 : nsIFrame::GetConstFrameSelection() const
7931 0 : {
7932 : nsIFrame* frame = const_cast<nsIFrame*>(this);
7933 1 : while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
7934 2 : nsITextControlFrame* tcf = do_QueryFrame(frame);
7935 1 : if (tcf) {
7936 1 : return tcf->GetOwnedFrameSelection();
7937 1 : }
7938 : frame = frame->GetParent();
7939 0 : }
7940 :
7941 : return PresShell()->ConstFrameSelection();
7942 0 : }
7943 :
7944 : bool
7945 : nsIFrame::IsFrameSelected() const
7946 0 : {
7947 : NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
7948 0 : "use the public IsSelected() instead");
7949 : return nsRange::IsNodeSelected(GetContent(), 0,
7950 0 : GetContent()->GetChildCount());
7951 0 : }
7952 :
7953 : nsresult
7954 : nsFrame::GetPointFromOffset(int32_t inOffset, nsPoint* outPoint)
7955 0 : {
7956 : MOZ_ASSERT(outPoint != nullptr, "Null parameter");
7957 0 : nsRect contentRect = GetContentRectRelativeToSelf();
7958 16 : nsPoint pt = contentRect.TopLeft();
7959 8 : if (mContent)
7960 16 : {
7961 : nsIContent* newContent = mContent->GetParent();
7962 8 : if (newContent){
7963 0 : int32_t newOffset = newContent->ComputeIndexOf(mContent);
7964 16 :
7965 : // Find the direction of the frame from the EmbeddingLevelProperty,
7966 : // which is the resolved bidi level set in
7967 : // nsBidiPresUtils::ResolveParagraph (odd levels = right-to-left).
7968 : // If the embedding level isn't set, just use the CSS direction
7969 : // property.
7970 : bool hasBidiData;
7971 : FrameBidiData bidiData = GetProperty(BidiDataProperty(), &hasBidiData);
7972 0 : bool isRTL = hasBidiData
7973 : ? IS_LEVEL_RTL(bidiData.embeddingLevel)
7974 0 : : StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
7975 0 : if ((!isRTL && inOffset > newOffset) ||
7976 0 : (isRTL && inOffset <= newOffset)) {
7977 : pt = contentRect.TopRight();
7978 0 : }
7979 : }
7980 : }
7981 : *outPoint = pt;
7982 8 : return NS_OK;
7983 8 : }
7984 :
7985 : nsresult
7986 : nsFrame::GetCharacterRectsInRange(int32_t aInOffset, int32_t aLength,
7987 0 : nsTArray<nsRect>& aOutRect)
7988 : {
7989 : /* no text */
7990 : return NS_ERROR_FAILURE;
7991 0 : }
7992 :
7993 : nsresult
7994 : nsFrame::GetChildFrameContainingOffset(int32_t inContentOffset, bool inHint, int32_t* outFrameContentOffset, nsIFrame **outChildFrame)
7995 0 : {
7996 : MOZ_ASSERT(outChildFrame && outFrameContentOffset, "Null parameter");
7997 0 : *outFrameContentOffset = (int32_t)inHint;
7998 0 : //the best frame to reflect any given offset would be a visible frame if possible
7999 : //i.e. we are looking for a valid frame to place the blinking caret
8000 : nsRect rect = GetRect();
8001 0 : if (!rect.width || !rect.height)
8002 11 : {
8003 : //if we have a 0 width or height then lets look for another frame that possibly has
8004 : //the same content. If we have no frames in flow then just let us return 'this' frame
8005 : nsIFrame* nextFlow = GetNextInFlow();
8006 0 : if (nextFlow)
8007 0 : return nextFlow->GetChildFrameContainingOffset(inContentOffset, inHint, outFrameContentOffset, outChildFrame);
8008 0 : }
8009 : *outChildFrame = this;
8010 0 : return NS_OK;
8011 11 : }
8012 :
8013 : //
8014 : // What I've pieced together about this routine:
8015 : // Starting with a block frame (from which a line frame can be gotten)
8016 : // and a line number, drill down and get the first/last selectable
8017 : // frame on that line, depending on aPos->mDirection.
8018 : // aOutSideLimit != 0 means ignore aLineStart, instead work from
8019 : // the end (if > 0) or beginning (if < 0).
8020 : //
8021 : nsresult
8022 : nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
8023 0 : nsPeekOffsetStruct *aPos,
8024 : nsIFrame *aBlockFrame,
8025 : int32_t aLineStart,
8026 : int8_t aOutSideLimit
8027 : )
8028 : {
8029 : //magic numbers aLineStart will be -1 for end of block 0 will be start of block
8030 : if (!aBlockFrame || !aPos)
8031 0 : return NS_ERROR_NULL_POINTER;
8032 :
8033 : aPos->mResultFrame = nullptr;
8034 0 : aPos->mResultContent = nullptr;
8035 0 : aPos->mAttach =
8036 0 : aPos->mDirection == eDirNext ? CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
8037 0 :
8038 : nsAutoLineIterator it = aBlockFrame->GetLineIterator();
8039 0 : if (!it)
8040 0 : return NS_ERROR_FAILURE;
8041 : int32_t searchingLine = aLineStart;
8042 0 : int32_t countLines = it->GetNumLines();
8043 0 : if (aOutSideLimit > 0) //start at end
8044 0 : searchingLine = countLines;
8045 : else if (aOutSideLimit <0)//start at beginning
8046 0 : searchingLine = -1;//"next" will be 0
8047 : else
8048 : if ((aPos->mDirection == eDirPrevious && searchingLine == 0) ||
8049 0 : (aPos->mDirection == eDirNext && searchingLine >= (countLines -1) )){
8050 0 : //we need to jump to new block frame.
8051 : return NS_ERROR_FAILURE;
8052 : }
8053 : int32_t lineFrameCount;
8054 : nsIFrame *resultFrame = nullptr;
8055 0 : nsIFrame *farStoppingFrame = nullptr; //we keep searching until we find a "this" frame then we go to next line
8056 0 : nsIFrame *nearStoppingFrame = nullptr; //if we are backing up from edge, stop here
8057 0 : nsIFrame *firstFrame;
8058 : nsIFrame *lastFrame;
8059 : nsRect rect;
8060 0 : bool isBeforeFirstFrame, isAfterLastFrame;
8061 : bool found = false;
8062 0 :
8063 : nsresult result = NS_OK;
8064 0 : while (!found)
8065 0 : {
8066 : if (aPos->mDirection == eDirPrevious)
8067 0 : searchingLine --;
8068 0 : else
8069 : searchingLine ++;
8070 0 : if ((aPos->mDirection == eDirPrevious && searchingLine < 0) ||
8071 0 : (aPos->mDirection == eDirNext && searchingLine >= countLines ))
8072 0 : {
8073 : //we need to jump to new block frame.
8074 : return NS_ERROR_FAILURE;
8075 : }
8076 : result = it->GetLine(searchingLine, &firstFrame, &lineFrameCount,
8077 0 : rect);
8078 0 : if (!lineFrameCount)
8079 0 : continue;
8080 : if (NS_SUCCEEDED(result)){
8081 0 : lastFrame = firstFrame;
8082 0 : for (;lineFrameCount > 1;lineFrameCount --){
8083 0 : //result = lastFrame->GetNextSibling(&lastFrame, searchingLine);
8084 : result = it->GetNextSiblingOnLine(lastFrame, searchingLine);
8085 0 : if (NS_FAILED(result) || !lastFrame){
8086 0 : NS_ERROR("GetLine promised more frames than could be found");
8087 0 : return NS_ERROR_FAILURE;
8088 0 : }
8089 : }
8090 : GetLastLeaf(aPresContext, &lastFrame);
8091 0 :
8092 : if (aPos->mDirection == eDirNext){
8093 0 : nearStoppingFrame = firstFrame;
8094 0 : farStoppingFrame = lastFrame;
8095 0 : }
8096 : else{
8097 : nearStoppingFrame = lastFrame;
8098 0 : farStoppingFrame = firstFrame;
8099 0 : }
8100 : nsPoint offset;
8101 0 : nsView * view; //used for call of get offset from view
8102 : aBlockFrame->GetOffsetFromView(offset,&view);
8103 0 : nsPoint newDesiredPos =
8104 : aPos->mDesiredPos - offset; //get desired position into blockframe coords
8105 0 : result = it->FindFrameAt(searchingLine, newDesiredPos, &resultFrame,
8106 0 : &isBeforeFirstFrame, &isAfterLastFrame);
8107 0 : if(NS_FAILED(result))
8108 0 : continue;
8109 0 : }
8110 :
8111 : if (NS_SUCCEEDED(result) && resultFrame)
8112 0 : {
8113 : //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines
8114 : nsAutoLineIterator newIt = resultFrame->GetLineIterator();
8115 0 : if (newIt)
8116 0 : {
8117 : aPos->mResultFrame = resultFrame;
8118 0 : return NS_OK;
8119 0 : }
8120 : //resultFrame is not a block frame
8121 : result = NS_ERROR_FAILURE;
8122 0 :
8123 : nsCOMPtr<nsIFrameEnumerator> frameTraversal;
8124 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
8125 0 : aPresContext, resultFrame,
8126 : ePostOrder,
8127 : false, // aVisual
8128 : aPos->mScrollViewStop,
8129 0 : false, // aFollowOOFs
8130 : false, // aSkipPopupChecks
8131 : false // aSkipShadow
8132 : );
8133 0 : if (NS_FAILED(result))
8134 0 : return result;
8135 0 :
8136 : nsIFrame *storeOldResultFrame = resultFrame;
8137 0 : while ( !found ){
8138 : nsPoint point;
8139 0 : nsRect tempRect = resultFrame->GetRect();
8140 0 : nsPoint offset;
8141 0 : nsView * view; //used for call of get offset from view
8142 : resultFrame->GetOffsetFromView(offset, &view);
8143 0 : if (!view) {
8144 0 : return NS_ERROR_FAILURE;
8145 0 : }
8146 : if (resultFrame->GetWritingMode().IsVertical()) {
8147 0 : point.y = aPos->mDesiredPos.y;
8148 0 : point.x = tempRect.width + offset.x;
8149 0 : } else {
8150 : point.y = tempRect.height + offset.y;
8151 0 : point.x = aPos->mDesiredPos.x;
8152 0 : }
8153 :
8154 : //special check. if we allow non-text selection then we can allow a hit location to fall before a table.
8155 : //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself)
8156 : nsIPresShell *shell = aPresContext->GetPresShell();
8157 0 : if (!shell)
8158 0 : return NS_ERROR_FAILURE;
8159 : int16_t isEditor = shell->GetSelectionFlags();
8160 0 : isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
8161 0 : if ( isEditor )
8162 0 : {
8163 : if (resultFrame->IsTableWrapperFrame()) {
8164 0 : if (((point.x - offset.x + tempRect.x)<0) || ((point.x - offset.x+ tempRect.x)>tempRect.width))//off left/right side
8165 0 : {
8166 : nsIContent* content = resultFrame->GetContent();
8167 0 : if (content)
8168 0 : {
8169 : nsIContent* parent = content->GetParent();
8170 0 : if (parent)
8171 0 : {
8172 : aPos->mResultContent = parent;
8173 0 : aPos->mContentOffset = parent->ComputeIndexOf(content);
8174 0 : aPos->mAttach = CARET_ASSOCIATE_BEFORE;
8175 0 : if ((point.x - offset.x+ tempRect.x)>tempRect.width)
8176 0 : {
8177 : aPos->mContentOffset++;//go to end of this frame
8178 0 : aPos->mAttach = CARET_ASSOCIATE_AFTER;
8179 0 : }
8180 : //result frame is the result frames parent.
8181 : aPos->mResultFrame = resultFrame->GetParent();
8182 0 : return NS_POSITION_BEFORE_TABLE;
8183 0 : }
8184 : }
8185 : }
8186 : }
8187 : }
8188 :
8189 : if (!resultFrame->HasView())
8190 0 : {
8191 : nsView* view;
8192 : nsPoint offset;
8193 0 : resultFrame->GetOffsetFromView(offset, &view);
8194 0 : ContentOffsets offsets =
8195 : resultFrame->GetContentOffsetsFromPoint(point - offset);
8196 0 : aPos->mResultContent = offsets.content;
8197 0 : aPos->mContentOffset = offsets.offset;
8198 0 : aPos->mAttach = offsets.associate;
8199 0 : if (offsets.content)
8200 0 : {
8201 : if (resultFrame->IsSelectable(nullptr)) {
8202 0 : found = true;
8203 0 : break;
8204 0 : }
8205 : }
8206 : }
8207 :
8208 : if (aPos->mDirection == eDirPrevious && (resultFrame == farStoppingFrame))
8209 0 : break;
8210 : if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame))
8211 0 : break;
8212 : //always try previous on THAT line if that fails go the other way
8213 : frameTraversal->Prev();
8214 0 : resultFrame = frameTraversal->CurrentItem();
8215 0 : if (!resultFrame)
8216 0 : return NS_ERROR_FAILURE;
8217 : }
8218 :
8219 : if (!found){
8220 0 : resultFrame = storeOldResultFrame;
8221 0 :
8222 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
8223 0 : aPresContext, resultFrame,
8224 : eLeaf,
8225 : false, // aVisual
8226 : aPos->mScrollViewStop,
8227 0 : false, // aFollowOOFs
8228 : false, // aSkipPopupChecks
8229 : false // aSkipShadow
8230 : );
8231 0 : }
8232 : while ( !found ){
8233 0 : nsPoint point = aPos->mDesiredPos;
8234 0 : nsView* view;
8235 : nsPoint offset;
8236 0 : resultFrame->GetOffsetFromView(offset, &view);
8237 0 : ContentOffsets offsets =
8238 : resultFrame->GetContentOffsetsFromPoint(point - offset);
8239 0 : aPos->mResultContent = offsets.content;
8240 0 : aPos->mContentOffset = offsets.offset;
8241 0 : aPos->mAttach = offsets.associate;
8242 0 : if (offsets.content)
8243 0 : {
8244 : if (resultFrame->IsSelectable(nullptr)) {
8245 0 : found = true;
8246 0 : if (resultFrame == farStoppingFrame)
8247 0 : aPos->mAttach = CARET_ASSOCIATE_BEFORE;
8248 0 : else
8249 : aPos->mAttach = CARET_ASSOCIATE_AFTER;
8250 0 : break;
8251 0 : }
8252 : }
8253 : if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame))
8254 0 : break;
8255 : if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame))
8256 0 : break;
8257 : //previous didnt work now we try "next"
8258 : frameTraversal->Next();
8259 0 : nsIFrame *tempFrame = frameTraversal->CurrentItem();
8260 0 : if (!tempFrame)
8261 0 : break;
8262 : resultFrame = tempFrame;
8263 0 : }
8264 : aPos->mResultFrame = resultFrame;
8265 0 : }
8266 : else {
8267 : //we need to jump to new block frame.
8268 : aPos->mAmount = eSelectLine;
8269 0 : aPos->mStartOffset = 0;
8270 0 : aPos->mAttach = aPos->mDirection == eDirNext ?
8271 0 : CARET_ASSOCIATE_BEFORE : CARET_ASSOCIATE_AFTER;
8272 : if (aPos->mDirection == eDirPrevious)
8273 0 : aPos->mStartOffset = -1;//start from end
8274 0 : return aBlockFrame->PeekOffset(aPos);
8275 0 : }
8276 : }
8277 : return NS_OK;
8278 : }
8279 :
8280 : nsIFrame::CaretPosition
8281 : nsIFrame::GetExtremeCaretPosition(bool aStart)
8282 0 : {
8283 : CaretPosition result;
8284 0 :
8285 : FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart, 0);
8286 0 : FrameContentRange range = GetRangeForFrame(targetFrame.frame);
8287 0 : result.mResultContent = range.content;
8288 0 : result.mContentOffset = aStart ? range.start : range.end;
8289 0 : return result;
8290 0 : }
8291 :
8292 : // Find the first (or last) descendant of the given frame
8293 : // which is either a block frame or a BRFrame.
8294 : static nsContentAndOffset
8295 : FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection)
8296 0 : {
8297 : nsContentAndOffset result;
8298 : result.mContent = nullptr;
8299 0 : result.mOffset = 0;
8300 0 :
8301 : if (aFrame->IsGeneratedContentFrame())
8302 0 : return result;
8303 0 :
8304 : // Treat form controls as inline leaves
8305 : // XXX we really need a way to determine whether a frame is inline-level
8306 : nsIFormControlFrame* fcf = do_QueryFrame(aFrame);
8307 0 : if (fcf)
8308 0 : return result;
8309 0 :
8310 : // Check the frame itself
8311 : // Fall through block-in-inline split frames because their mContent is
8312 : // the content of the inline frames they were created from. The
8313 : // first/last child of such frames is the real block frame we're
8314 : // looking for.
8315 : if ((nsLayoutUtils::GetAsBlock(aFrame) &&
8316 0 : !(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) ||
8317 0 : aFrame->IsBrFrame()) {
8318 0 : nsIContent* content = aFrame->GetContent();
8319 0 : result.mContent = content->GetParent();
8320 0 : // In some cases (bug 310589, bug 370174) we end up here with a null content.
8321 : // This probably shouldn't ever happen, but since it sometimes does, we want
8322 : // to avoid crashing here.
8323 : NS_ASSERTION(result.mContent, "Unexpected orphan content");
8324 0 : if (result.mContent)
8325 0 : result.mOffset = result.mContent->ComputeIndexOf(content) +
8326 0 : (aDirection == eDirPrevious ? 1 : 0);
8327 0 : return result;
8328 0 : }
8329 :
8330 : // If this is a preformatted text frame, see if it ends with a newline
8331 : if (aFrame->HasSignificantTerminalNewline()) {
8332 0 : int32_t startOffset, endOffset;
8333 : aFrame->GetOffsets(startOffset, endOffset);
8334 0 : result.mContent = aFrame->GetContent();
8335 0 : result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1);
8336 0 : return result;
8337 0 : }
8338 :
8339 : // Iterate over children and call ourselves recursively
8340 : if (aDirection == eDirPrevious) {
8341 0 : nsIFrame* child = aFrame->GetChildList(nsIFrame::kPrincipalList).LastChild();
8342 0 : while(child && !result.mContent) {
8343 0 : result = FindBlockFrameOrBR(child, aDirection);
8344 0 : child = child->GetPrevSibling();
8345 0 : }
8346 : } else { // eDirNext
8347 : nsIFrame* child = aFrame->PrincipalChildList().FirstChild();
8348 0 : while(child && !result.mContent) {
8349 0 : result = FindBlockFrameOrBR(child, aDirection);
8350 0 : child = child->GetNextSibling();
8351 0 : }
8352 : }
8353 : return result;
8354 0 : }
8355 :
8356 : nsresult
8357 : nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
8358 0 : {
8359 : nsIFrame* frame = this;
8360 0 : nsContentAndOffset blockFrameOrBR;
8361 : blockFrameOrBR.mContent = nullptr;
8362 0 : bool reachedBlockAncestor = !!nsLayoutUtils::GetAsBlock(frame);
8363 0 :
8364 : // Go through containing frames until reaching a block frame.
8365 : // In each step, search the previous (or next) siblings for the closest
8366 : // "stop frame" (a block frame or a BRFrame).
8367 : // If found, set it to be the selection boundray and abort.
8368 :
8369 : if (aPos->mDirection == eDirPrevious) {
8370 0 : while (!reachedBlockAncestor) {
8371 0 : nsIFrame* parent = frame->GetParent();
8372 0 : // Treat a frame associated with the root content as if it were a block frame.
8373 : if (!frame->mContent || !frame->mContent->GetParent()) {
8374 0 : reachedBlockAncestor = true;
8375 : break;
8376 : }
8377 : nsIFrame* sibling = frame->GetPrevSibling();
8378 0 : while (sibling && !blockFrameOrBR.mContent) {
8379 0 : blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirPrevious);
8380 0 : sibling = sibling->GetPrevSibling();
8381 0 : }
8382 : if (blockFrameOrBR.mContent) {
8383 0 : aPos->mResultContent = blockFrameOrBR.mContent;
8384 0 : aPos->mContentOffset = blockFrameOrBR.mOffset;
8385 0 : break;
8386 0 : }
8387 : frame = parent;
8388 0 : reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr);
8389 0 : }
8390 : if (reachedBlockAncestor) { // no "stop frame" found
8391 0 : aPos->mResultContent = frame->GetContent();
8392 0 : aPos->mContentOffset = 0;
8393 0 : }
8394 : } else { // eDirNext
8395 : while (!reachedBlockAncestor) {
8396 0 : nsIFrame* parent = frame->GetParent();
8397 0 : // Treat a frame associated with the root content as if it were a block frame.
8398 : if (!frame->mContent || !frame->mContent->GetParent()) {
8399 0 : reachedBlockAncestor = true;
8400 : break;
8401 : }
8402 : nsIFrame* sibling = frame;
8403 : while (sibling && !blockFrameOrBR.mContent) {
8404 0 : blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirNext);
8405 0 : sibling = sibling->GetNextSibling();
8406 0 : }
8407 : if (blockFrameOrBR.mContent) {
8408 0 : aPos->mResultContent = blockFrameOrBR.mContent;
8409 0 : aPos->mContentOffset = blockFrameOrBR.mOffset;
8410 0 : break;
8411 0 : }
8412 : frame = parent;
8413 0 : reachedBlockAncestor = !!nsLayoutUtils::GetAsBlock(frame);
8414 0 : }
8415 : if (reachedBlockAncestor) { // no "stop frame" found
8416 0 : aPos->mResultContent = frame->GetContent();
8417 0 : if (aPos->mResultContent)
8418 0 : aPos->mContentOffset = aPos->mResultContent->GetChildCount();
8419 0 : }
8420 : }
8421 : return NS_OK;
8422 0 : }
8423 :
8424 : // Determine movement direction relative to frame
8425 : static bool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, bool aVisual)
8426 0 : {
8427 : bool isReverseDirection = aVisual && IsReversedDirectionFrame(frame);
8428 0 : return aDirection == (isReverseDirection ? eDirPrevious : eDirNext);
8429 0 : }
8430 :
8431 : nsresult
8432 : nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
8433 0 : {
8434 : if (!aPos)
8435 0 : return NS_ERROR_NULL_POINTER;
8436 : nsresult result = NS_ERROR_FAILURE;
8437 0 :
8438 : if (mState & NS_FRAME_IS_DIRTY)
8439 0 : return NS_ERROR_UNEXPECTED;
8440 :
8441 : // Translate content offset to be relative to frame
8442 : FrameContentRange range = GetRangeForFrame(this);
8443 0 : int32_t offset = aPos->mStartOffset - range.start;
8444 0 : nsIFrame* current = this;
8445 0 :
8446 : switch (aPos->mAmount) {
8447 0 : case eSelectCharacter:
8448 : case eSelectCluster:
8449 : {
8450 : bool eatingNonRenderableWS = false;
8451 0 : nsIFrame::FrameSearchResult peekSearchState = CONTINUE;
8452 0 : bool jumpedLine = false;
8453 0 : bool movedOverNonSelectableText = false;
8454 0 :
8455 : while (peekSearchState != FOUND) {
8456 0 : bool movingInFrameDirection =
8457 : IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
8458 0 :
8459 : if (eatingNonRenderableWS) {
8460 0 : peekSearchState = current->PeekOffsetNoAmount(movingInFrameDirection, &offset);
8461 0 : } else {
8462 : PeekOffsetCharacterOptions options;
8463 0 : options.mRespectClusters = aPos->mAmount == eSelectCluster;
8464 0 : peekSearchState = current->PeekOffsetCharacter(movingInFrameDirection,
8465 0 : &offset, options);
8466 0 : }
8467 :
8468 : movedOverNonSelectableText |= (peekSearchState == CONTINUE_UNSELECTABLE);
8469 0 :
8470 : if (peekSearchState != FOUND) {
8471 0 : bool movedOverNonSelectable = false;
8472 0 : result =
8473 : current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
8474 0 : aPos->mJumpLines, aPos->mScrollViewStop,
8475 0 : ¤t, &offset, &jumpedLine,
8476 : &movedOverNonSelectable);
8477 0 : if (NS_FAILED(result))
8478 0 : return result;
8479 0 :
8480 : // If we jumped lines, it's as if we found a character, but we still need
8481 : // to eat non-renderable content on the new line.
8482 : if (jumpedLine)
8483 0 : eatingNonRenderableWS = true;
8484 0 :
8485 : // Remember if we moved over non-selectable text when finding another frame.
8486 : if (movedOverNonSelectable) {
8487 0 : movedOverNonSelectableText = true;
8488 0 : }
8489 : }
8490 :
8491 : // Found frame, but because we moved over non selectable text we want the offset
8492 : // to be at the frame edge. Note that if we are extending the selection, this
8493 : // doesn't matter.
8494 : if (peekSearchState == FOUND && movedOverNonSelectableText &&
8495 0 : !aPos->mExtend)
8496 0 : {
8497 : int32_t start, end;
8498 : current->GetOffsets(start, end);
8499 0 : offset = aPos->mDirection == eDirNext ? 0 : end - start;
8500 0 : }
8501 : }
8502 :
8503 : // Set outputs
8504 : range = GetRangeForFrame(current);
8505 0 : aPos->mResultFrame = current;
8506 0 : aPos->mResultContent = range.content;
8507 0 : // Output offset is relative to content, not frame
8508 : aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
8509 0 : // If we're dealing with a text frame and moving backward positions us at
8510 : // the end of that line, decrease the offset by one to make sure that
8511 : // we're placed before the linefeed character on the previous line.
8512 : if (offset < 0 && jumpedLine &&
8513 0 : aPos->mDirection == eDirPrevious &&
8514 0 : current->HasSignificantTerminalNewline()) {
8515 0 : --aPos->mContentOffset;
8516 0 : }
8517 :
8518 : break;
8519 0 : }
8520 : case eSelectWordNoSpace:
8521 : // eSelectWordNoSpace means that we should not be eating any whitespace when
8522 : // moving to the adjacent word. This means that we should set aPos->
8523 : // mWordMovementType to eEndWord if we're moving forwards, and to eStartWord
8524 : // if we're moving backwards.
8525 : if (aPos->mDirection == eDirPrevious) {
8526 0 : aPos->mWordMovementType = eStartWord;
8527 0 : } else {
8528 : aPos->mWordMovementType = eEndWord;
8529 0 : }
8530 : // Intentionally fall through the eSelectWord case.
8531 : MOZ_FALLTHROUGH;
8532 : case eSelectWord:
8533 : {
8534 : // wordSelectEatSpace means "are we looking for a boundary between whitespace
8535 : // and non-whitespace (in the direction we're moving in)".
8536 : // It is true when moving forward and looking for a beginning of a word, or
8537 : // when moving backwards and looking for an end of a word.
8538 : bool wordSelectEatSpace;
8539 : if (aPos->mWordMovementType != eDefaultBehavior) {
8540 0 : // aPos->mWordMovementType possible values:
8541 : // eEndWord: eat the space if we're moving backwards
8542 : // eStartWord: eat the space if we're moving forwards
8543 : wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious));
8544 0 : }
8545 : else {
8546 : // Use the hidden preference which is based on operating system behavior.
8547 : // This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
8548 : // When going backwards, the start of the word is always used, on every operating system.
8549 : wordSelectEatSpace = aPos->mDirection == eDirNext &&
8550 0 : Preferences::GetBool("layout.word_select.eat_space_to_next_word");
8551 0 : }
8552 :
8553 : // mSawBeforeType means "we already saw characters of the type
8554 : // before the boundary we're looking for". Examples:
8555 : // 1. If we're moving forward, looking for a word beginning (i.e. a boundary
8556 : // between whitespace and non-whitespace), then eatingWS==true means
8557 : // "we already saw some whitespace".
8558 : // 2. If we're moving backward, looking for a word beginning (i.e. a boundary
8559 : // between non-whitespace and whitespace), then eatingWS==true means
8560 : // "we already saw some non-whitespace".
8561 : PeekWordState state;
8562 0 : int32_t offsetAdjustment = 0;
8563 0 : bool done = false;
8564 0 : while (!done) {
8565 0 : bool movingInFrameDirection =
8566 : IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
8567 0 :
8568 : done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace,
8569 0 : aPos->mIsKeyboardSelect, &offset, &state) == FOUND;
8570 0 :
8571 : if (!done) {
8572 0 : nsIFrame* nextFrame;
8573 : int32_t nextFrameOffset;
8574 : bool jumpedLine, movedOverNonSelectableText;
8575 : result =
8576 : current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
8577 0 : aPos->mJumpLines, aPos->mScrollViewStop,
8578 0 : &nextFrame, &nextFrameOffset, &jumpedLine,
8579 : &movedOverNonSelectableText);
8580 0 : // We can't jump lines if we're looking for whitespace following
8581 : // non-whitespace, and we already encountered non-whitespace.
8582 : if (NS_FAILED(result) ||
8583 0 : (jumpedLine && !wordSelectEatSpace && state.mSawBeforeType)) {
8584 0 : done = true;
8585 0 : // If we've crossed the line boundary, check to make sure that we
8586 : // have not consumed a trailing newline as whitesapce if it's significant.
8587 : if (jumpedLine && wordSelectEatSpace &&
8588 0 : current->HasSignificantTerminalNewline()) {
8589 0 : offsetAdjustment = -1;
8590 0 : }
8591 : } else {
8592 : if (jumpedLine) {
8593 0 : state.mContext.Truncate();
8594 0 : }
8595 : current = nextFrame;
8596 0 : offset = nextFrameOffset;
8597 0 : // Jumping a line is equivalent to encountering whitespace
8598 : if (wordSelectEatSpace && jumpedLine)
8599 0 : state.SetSawBeforeType();
8600 0 : }
8601 : }
8602 : }
8603 :
8604 : // Set outputs
8605 : range = GetRangeForFrame(current);
8606 0 : aPos->mResultFrame = current;
8607 0 : aPos->mResultContent = range.content;
8608 0 : // Output offset is relative to content, not frame
8609 : aPos->mContentOffset = (offset < 0 ? range.end : range.start + offset) + offsetAdjustment;
8610 0 : break;
8611 : }
8612 : case eSelectLine :
8613 : {
8614 : nsAutoLineIterator iter;
8615 0 : nsIFrame *blockFrame = this;
8616 0 :
8617 : while (NS_FAILED(result)){
8618 0 : int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
8619 0 : if (thisLine < 0)
8620 0 : return NS_ERROR_FAILURE;
8621 : iter = blockFrame->GetLineIterator();
8622 0 : NS_ASSERTION(iter, "GetLineNumber() succeeded but no block frame?");
8623 0 : result = NS_OK;
8624 :
8625 : int edgeCase = 0; // no edge case. this should look at thisLine
8626 :
8627 : bool doneLooping = false; // tells us when no more block frames hit.
8628 : // this part will find a frame or a block frame. if it's a block frame
8629 : // it will "drill down" to find a viable frame or it will return an error.
8630 : nsIFrame *lastFrame = this;
8631 : do {
8632 : result = nsFrame::GetNextPrevLineFromeBlockFrame(PresContext(),
8633 0 : aPos,
8634 : blockFrame,
8635 : thisLine,
8636 : edgeCase); // start from thisLine
8637 0 :
8638 : // we came back to same spot! keep going
8639 : if (NS_SUCCEEDED(result) &&
8640 0 : (!aPos->mResultFrame || aPos->mResultFrame == lastFrame)) {
8641 0 : aPos->mResultFrame = nullptr;
8642 0 : if (aPos->mDirection == eDirPrevious)
8643 0 : thisLine--;
8644 0 : else
8645 : thisLine++;
8646 0 : } else // if failure or success with different frame.
8647 : doneLooping = true; // do not continue with while loop
8648 :
8649 : lastFrame = aPos->mResultFrame; // set last frame
8650 0 :
8651 : // make sure block element is not the same as the one we had before
8652 : if (NS_SUCCEEDED(result) &&
8653 0 : aPos->mResultFrame &&
8654 0 : blockFrame != aPos->mResultFrame) {
8655 0 : /* SPECIAL CHECK FOR TABLE NAVIGATION
8656 : tables need to navigate also and the frame that supports it is
8657 : nsTableRowGroupFrame which is INSIDE nsTableWrapperFrame.
8658 : If we have stumbled onto an nsTableWrapperFrame we need to drill
8659 : into nsTableRowGroup if we hit a header or footer that's ok just
8660 : go into them.
8661 : */
8662 : bool searchTableBool = false;
8663 0 : if (aPos->mResultFrame->IsTableWrapperFrame() ||
8664 0 : aPos->mResultFrame->IsTableCellFrame()) {
8665 0 : nsIFrame* frame = aPos->mResultFrame->PrincipalChildList().FirstChild();
8666 0 : // got the table frame now
8667 : // ok time to drill down to find iterator
8668 : while (frame) {
8669 0 : iter = frame->GetLineIterator();
8670 0 : if (iter) {
8671 0 : aPos->mResultFrame = frame;
8672 0 : searchTableBool = true;
8673 0 : result = NS_OK;
8674 0 : break; // while(frame)
8675 0 : }
8676 : result = NS_ERROR_FAILURE;
8677 0 : frame = frame->PrincipalChildList().FirstChild();
8678 0 : }
8679 : }
8680 :
8681 : if (!searchTableBool) {
8682 0 : iter = aPos->mResultFrame->GetLineIterator();
8683 0 : result = iter ? NS_OK : NS_ERROR_FAILURE;
8684 0 : }
8685 :
8686 : // we've struck another block element!
8687 : if (NS_SUCCEEDED(result) && iter) {
8688 0 : doneLooping = false;
8689 0 : if (aPos->mDirection == eDirPrevious)
8690 0 : edgeCase = 1; // far edge, search from end backwards
8691 : else
8692 : edgeCase = -1; // near edge search from beginning onwards
8693 0 : thisLine = 0; // this line means nothing now.
8694 0 : // everything else means something so keep looking "inside" the block
8695 : blockFrame = aPos->mResultFrame;
8696 0 : } else {
8697 : // THIS is to mean that everything is ok to the containing while loop
8698 : result = NS_OK;
8699 : break;
8700 : }
8701 : }
8702 : } while (!doneLooping);
8703 0 : }
8704 : return result;
8705 : }
8706 :
8707 : case eSelectParagraph:
8708 : return PeekOffsetParagraph(aPos);
8709 0 :
8710 : case eSelectBeginLine:
8711 : case eSelectEndLine:
8712 : {
8713 : // Adjusted so that the caret can't get confused when content changes
8714 : nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this);
8715 0 : int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
8716 0 : if (thisLine < 0)
8717 0 : return NS_ERROR_FAILURE;
8718 : nsAutoLineIterator it = blockFrame->GetLineIterator();
8719 0 : NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
8720 0 :
8721 : int32_t lineFrameCount;
8722 : nsIFrame *firstFrame;
8723 : nsRect usedRect;
8724 0 : nsIFrame* baseFrame = nullptr;
8725 0 : bool endOfLine = (eSelectEndLine == aPos->mAmount);
8726 0 :
8727 : if (aPos->mVisual && PresContext()->BidiEnabled()) {
8728 0 : bool lineIsRTL = it->GetDirection();
8729 0 : bool isReordered;
8730 : nsIFrame *lastFrame;
8731 : result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
8732 0 : baseFrame = endOfLine ? lastFrame : firstFrame;
8733 0 : if (baseFrame) {
8734 0 : bool frameIsRTL =
8735 : (nsBidiPresUtils::FrameDirection(baseFrame) == NSBIDI_RTL);
8736 0 : // If the direction of the frame on the edge is opposite to
8737 : // that of the line, we'll need to drill down to its opposite
8738 : // end, so reverse endOfLine.
8739 : if (frameIsRTL != lineIsRTL) {
8740 0 : endOfLine = !endOfLine;
8741 0 : }
8742 : }
8743 : } else {
8744 : it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect);
8745 0 :
8746 : nsIFrame* frame = firstFrame;
8747 0 : for (int32_t count = lineFrameCount; count;
8748 0 : --count, frame = frame->GetNextSibling()) {
8749 : if (!frame->IsGeneratedContentFrame()) {
8750 0 : // When jumping to the end of the line with the "end" key,
8751 : // skip over brFrames
8752 : if (endOfLine && lineFrameCount > 1 && frame->IsBrFrame()) {
8753 0 : continue;
8754 : }
8755 : baseFrame = frame;
8756 0 : if (!endOfLine)
8757 0 : break;
8758 : }
8759 : }
8760 : }
8761 : if (!baseFrame)
8762 0 : return NS_ERROR_FAILURE;
8763 : FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame,
8764 : endOfLine, 0);
8765 0 : FrameContentRange range = GetRangeForFrame(targetFrame.frame);
8766 0 : aPos->mResultContent = range.content;
8767 0 : aPos->mContentOffset = endOfLine ? range.end : range.start;
8768 0 : if (endOfLine && targetFrame.frame->HasSignificantTerminalNewline()) {
8769 0 : // Do not position the caret after the terminating newline if we're
8770 : // trying to move to the end of line (see bug 596506)
8771 : --aPos->mContentOffset;
8772 0 : }
8773 : aPos->mResultFrame = targetFrame.frame;
8774 0 : aPos->mAttach = aPos->mContentOffset == range.start ?
8775 0 : CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
8776 : if (!range.content)
8777 0 : return NS_ERROR_FAILURE;
8778 : return NS_OK;
8779 0 : }
8780 :
8781 : default:
8782 : {
8783 : NS_ASSERTION(false, "Invalid amount");
8784 0 : return NS_ERROR_FAILURE;
8785 0 : }
8786 : }
8787 : return NS_OK;
8788 : }
8789 :
8790 : nsIFrame::FrameSearchResult
8791 : nsFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
8792 0 : {
8793 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
8794 0 : // Sure, we can stop right here.
8795 : return FOUND;
8796 0 : }
8797 :
8798 : nsIFrame::FrameSearchResult
8799 : nsFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
8800 0 : PeekOffsetCharacterOptions aOptions)
8801 : {
8802 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
8803 0 : int32_t startOffset = *aOffset;
8804 0 : // A negative offset means "end of frame", which in our case means offset 1.
8805 : if (startOffset < 0)
8806 0 : startOffset = 1;
8807 0 : if (aForward == (startOffset == 0)) {
8808 0 : // We're before the frame and moving forward, or after it and moving backwards:
8809 : // skip to the other side and we're done.
8810 : *aOffset = 1 - startOffset;
8811 0 : return FOUND;
8812 0 : }
8813 : return CONTINUE;
8814 : }
8815 :
8816 : nsIFrame::FrameSearchResult
8817 : nsFrame::PeekOffsetWord(bool aForward,
8818 0 : bool aWordSelectEatSpace,
8819 : bool aIsKeyboardSelect,
8820 : int32_t* aOffset,
8821 : PeekWordState* aState)
8822 : {
8823 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
8824 0 : int32_t startOffset = *aOffset;
8825 0 : // This isn't text, so truncate the context
8826 : aState->mContext.Truncate();
8827 0 : if (startOffset < 0)
8828 0 : startOffset = 1;
8829 0 : if (aForward == (startOffset == 0)) {
8830 0 : // We're before the frame and moving forward, or after it and moving backwards.
8831 : // If we're looking for non-whitespace, we found it (without skipping this frame).
8832 : if (!aState->mAtStart) {
8833 0 : if (aState->mLastCharWasPunctuation) {
8834 0 : // We're not punctuation, so this is a punctuation boundary.
8835 : if (BreakWordBetweenPunctuation(aState, aForward, false, false, aIsKeyboardSelect))
8836 0 : return FOUND;
8837 : } else {
8838 : // This is not a punctuation boundary.
8839 : if (aWordSelectEatSpace && aState->mSawBeforeType)
8840 0 : return FOUND;
8841 : }
8842 : }
8843 : // Otherwise skip to the other side and note that we encountered non-whitespace.
8844 : *aOffset = 1 - startOffset;
8845 0 : aState->Update(false, // not punctuation
8846 : false // not whitespace
8847 : );
8848 0 : if (!aWordSelectEatSpace)
8849 0 : aState->SetSawBeforeType();
8850 0 : }
8851 : return CONTINUE;
8852 : }
8853 :
8854 : bool
8855 : nsFrame::BreakWordBetweenPunctuation(const PeekWordState* aState,
8856 0 : bool aForward,
8857 : bool aPunctAfter, bool aWhitespaceAfter,
8858 : bool aIsKeyboardSelect)
8859 : {
8860 : NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation,
8861 0 : "Call this only at punctuation boundaries");
8862 : if (aState->mLastCharWasWhitespace) {
8863 0 : // We always stop between whitespace and punctuation
8864 : return true;
8865 : }
8866 : if (!Preferences::GetBool("layout.word_select.stop_at_punctuation")) {
8867 0 : // When this pref is false, we never stop at a punctuation boundary unless
8868 : // it's followed by whitespace (in the relevant direction).
8869 : return aWhitespaceAfter;
8870 : }
8871 : if (!aIsKeyboardSelect) {
8872 0 : // mouse caret movement (e.g. word selection) always stops at every punctuation boundary
8873 : return true;
8874 : }
8875 : bool afterPunct = aForward ? aState->mLastCharWasPunctuation : aPunctAfter;
8876 0 : if (!afterPunct) {
8877 0 : // keyboard caret movement only stops after punctuation (in content order)
8878 : return false;
8879 : }
8880 : // Stop only if we've seen some non-punctuation since the last whitespace;
8881 : // don't stop after punctuation that follows whitespace.
8882 : return aState->mSeenNonPunctuationSinceWhitespace;
8883 0 : }
8884 :
8885 : nsresult
8886 : nsFrame::CheckVisibility(nsPresContext* , int32_t , int32_t , bool , bool *, bool *)
8887 0 : {
8888 : return NS_ERROR_NOT_IMPLEMENTED;
8889 0 : }
8890 :
8891 :
8892 : int32_t
8893 : nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
8894 0 : {
8895 : NS_ASSERTION(aFrame, "null aFrame");
8896 0 : nsIFrame* blockFrame = aFrame;
8897 0 : nsIFrame* thisBlock;
8898 : nsAutoLineIterator it;
8899 0 : nsresult result = NS_ERROR_FAILURE;
8900 0 : while (NS_FAILED(result) && blockFrame)
8901 0 : {
8902 : thisBlock = blockFrame;
8903 0 : if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8904 0 : //if we are searching for a frame that is not in flow we will not find it.
8905 : //we must instead look for its placeholder
8906 : if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
8907 0 : // abspos continuations don't have placeholders, get the fif
8908 : thisBlock = thisBlock->FirstInFlow();
8909 0 : }
8910 : thisBlock = thisBlock->GetPlaceholderFrame();
8911 0 : if (!thisBlock)
8912 0 : return -1;
8913 : }
8914 : blockFrame = thisBlock->GetParent();
8915 0 : result = NS_OK;
8916 0 : if (blockFrame) {
8917 0 : if (aLockScroll && blockFrame->IsScrollFrame())
8918 0 : return -1;
8919 : it = blockFrame->GetLineIterator();
8920 0 : if (!it)
8921 0 : result = NS_ERROR_FAILURE;
8922 0 : }
8923 : }
8924 : if (!blockFrame || !it)
8925 0 : return -1;
8926 :
8927 : if (aContainingBlock)
8928 0 : *aContainingBlock = blockFrame;
8929 0 : return it->FindLineContaining(thisBlock);
8930 0 : }
8931 :
8932 : nsresult
8933 : nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
8934 0 : bool aJumpLines, bool aScrollViewStop,
8935 : nsIFrame** aOutFrame, int32_t* aOutOffset,
8936 : bool* aOutJumpedLine, bool* aOutMovedOverNonSelectableText)
8937 : {
8938 : nsresult result;
8939 :
8940 : if (!aOutFrame || !aOutOffset || !aOutJumpedLine)
8941 0 : return NS_ERROR_NULL_POINTER;
8942 :
8943 : nsPresContext* presContext = PresContext();
8944 0 : *aOutFrame = nullptr;
8945 0 : *aOutOffset = 0;
8946 0 : *aOutJumpedLine = false;
8947 0 : *aOutMovedOverNonSelectableText = false;
8948 0 :
8949 : // Find the prev/next selectable frame
8950 : bool selectable = false;
8951 0 : nsIFrame *traversedFrame = this;
8952 0 : while (!selectable) {
8953 0 : nsIFrame *blockFrame;
8954 :
8955 : int32_t thisLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &blockFrame);
8956 0 : if (thisLine < 0)
8957 0 : return NS_ERROR_FAILURE;
8958 0 :
8959 : nsAutoLineIterator it = blockFrame->GetLineIterator();
8960 0 : NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
8961 0 :
8962 : bool atLineEdge;
8963 : nsIFrame *firstFrame;
8964 : nsIFrame *lastFrame;
8965 : if (aVisual && presContext->BidiEnabled()) {
8966 0 : bool lineIsRTL = it->GetDirection();
8967 0 : bool isReordered;
8968 : result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
8969 0 : nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
8970 0 : if (*framePtr) {
8971 0 : bool frameIsRTL =
8972 : (nsBidiPresUtils::FrameDirection(*framePtr) == NSBIDI_RTL);
8973 0 : if ((frameIsRTL == lineIsRTL) == (aDirection == eDirPrevious)) {
8974 0 : nsFrame::GetFirstLeaf(presContext, framePtr);
8975 0 : } else {
8976 : nsFrame::GetLastLeaf(presContext, framePtr);
8977 0 : }
8978 : atLineEdge = *framePtr == traversedFrame;
8979 0 : } else {
8980 : atLineEdge = true;
8981 : }
8982 : } else {
8983 : nsRect nonUsedRect;
8984 0 : int32_t lineFrameCount;
8985 : result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,
8986 0 : nonUsedRect);
8987 0 : if (NS_FAILED(result))
8988 0 : return result;
8989 0 :
8990 : if (aDirection == eDirPrevious) {
8991 0 : nsFrame::GetFirstLeaf(presContext, &firstFrame);
8992 0 : atLineEdge = firstFrame == traversedFrame;
8993 0 : } else { // eDirNext
8994 : lastFrame = firstFrame;
8995 0 : for (;lineFrameCount > 1;lineFrameCount --){
8996 0 : result = it->GetNextSiblingOnLine(lastFrame, thisLine);
8997 0 : if (NS_FAILED(result) || !lastFrame){
8998 0 : NS_ERROR("should not be reached nsFrame");
8999 0 : return NS_ERROR_FAILURE;
9000 0 : }
9001 : }
9002 : nsFrame::GetLastLeaf(presContext, &lastFrame);
9003 0 : atLineEdge = lastFrame == traversedFrame;
9004 0 : }
9005 : }
9006 :
9007 : if (atLineEdge) {
9008 0 : *aOutJumpedLine = true;
9009 0 : if (!aJumpLines)
9010 0 : return NS_ERROR_FAILURE; //we are done. cannot jump lines
9011 : }
9012 :
9013 : nsCOMPtr<nsIFrameEnumerator> frameTraversal;
9014 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
9015 0 : presContext, traversedFrame,
9016 : eLeaf,
9017 : aVisual && presContext->BidiEnabled(),
9018 0 : aScrollViewStop,
9019 : true, // aFollowOOFs
9020 : false, // aSkipPopupChecks
9021 : false // aSkipShadow
9022 : );
9023 0 : if (NS_FAILED(result))
9024 0 : return result;
9025 0 :
9026 : if (aDirection == eDirNext)
9027 0 : frameTraversal->Next();
9028 0 : else
9029 : frameTraversal->Prev();
9030 0 :
9031 : traversedFrame = frameTraversal->CurrentItem();
9032 0 :
9033 : // Skip anonymous elements, but watch out for generated content
9034 : if (!traversedFrame ||
9035 0 : (!traversedFrame->IsGeneratedContentFrame() &&
9036 0 : traversedFrame->GetContent()->IsRootOfNativeAnonymousSubtree())) {
9037 0 : return NS_ERROR_FAILURE;
9038 : }
9039 :
9040 : // Skip brFrames, but only if they are not the only frame in the line
9041 : if (atLineEdge && aDirection == eDirPrevious &&
9042 0 : traversedFrame->IsBrFrame()) {
9043 0 : int32_t lineFrameCount;
9044 : nsIFrame *currentBlockFrame, *currentFirstFrame;
9045 : nsRect usedRect;
9046 0 : int32_t currentLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, ¤tBlockFrame);
9047 0 : nsAutoLineIterator iter = currentBlockFrame->GetLineIterator();
9048 0 : result = iter->GetLine(currentLine, ¤tFirstFrame, &lineFrameCount, usedRect);
9049 0 : if (NS_FAILED(result)) {
9050 0 : return result;
9051 0 : }
9052 : if (lineFrameCount > 1) {
9053 0 : continue;
9054 0 : }
9055 : }
9056 :
9057 : selectable = traversedFrame->IsSelectable(nullptr);
9058 0 : if (!selectable) {
9059 0 : *aOutMovedOverNonSelectableText = true;
9060 0 : }
9061 : } // while (!selectable)
9062 :
9063 : *aOutOffset = (aDirection == eDirNext) ? 0 : -1;
9064 0 :
9065 : if (aVisual && IsReversedDirectionFrame(traversedFrame)) {
9066 0 : // The new frame is reverse-direction, go to the other end
9067 : *aOutOffset = -1 - *aOutOffset;
9068 0 : }
9069 : *aOutFrame = traversedFrame;
9070 0 : return NS_OK;
9071 0 : }
9072 :
9073 : nsView* nsIFrame::GetClosestView(nsPoint* aOffset) const
9074 269 : {
9075 : nsPoint offset(0,0);
9076 0 : for (const nsIFrame *f = this; f; f = f->GetParent()) {
9077 0 : if (f->HasView()) {
9078 1010 : if (aOffset)
9079 269 : *aOffset = offset;
9080 0 : return f->GetView();
9081 269 : }
9082 : offset += f->GetPosition();
9083 236 : }
9084 :
9085 : NS_NOTREACHED("No view on any parent? How did that happen?");
9086 0 : return nullptr;
9087 0 : }
9088 :
9089 :
9090 : /* virtual */ void
9091 : nsFrame::ChildIsDirty(nsIFrame* aChild)
9092 0 : {
9093 : NS_NOTREACHED("should never be called on a frame that doesn't inherit from "
9094 0 : "nsContainerFrame");
9095 : }
9096 0 :
9097 :
9098 : #ifdef ACCESSIBILITY
9099 : a11y::AccType
9100 : nsFrame::AccessibleType()
9101 0 : {
9102 : if (IsTableCaption() && !GetRect().IsEmpty()) {
9103 0 : return a11y::eHTMLCaptionType;
9104 : }
9105 : return a11y::eNoType;
9106 0 : }
9107 : #endif
9108 :
9109 : bool
9110 : nsIFrame::ClearOverflowRects()
9111 0 : {
9112 : if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) {
9113 1 : return false;
9114 : }
9115 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
9116 0 : DeleteProperty(OverflowAreasProperty());
9117 9 : }
9118 : mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
9119 9 : return true;
9120 0 : }
9121 :
9122 : /** Set the overflowArea rect, storing it as deltas or a separate rect
9123 : * depending on its size in relation to the primary frame rect.
9124 : */
9125 : bool
9126 : nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
9127 61 : {
9128 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
9129 61 : nsOverflowAreas* overflow = GetOverflowAreasProperty();
9130 0 : bool changed = *overflow != aOverflowAreas;
9131 26 : *overflow = aOverflowAreas;
9132 0 :
9133 : // Don't bother with converting to the deltas form if we already
9134 : // have a property.
9135 : return changed;
9136 0 : }
9137 :
9138 : const nsRect& vis = aOverflowAreas.VisualOverflow();
9139 0 : uint32_t l = -vis.x, // left edge: positive delta is leftwards
9140 0 : t = -vis.y, // top: positive is upwards
9141 0 : r = vis.XMost() - mRect.width, // right: positive is rightwards
9142 0 : b = vis.YMost() - mRect.height; // bottom: positive is downwards
9143 0 : if (aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) &&
9144 140 : l <= NS_FRAME_OVERFLOW_DELTA_MAX &&
9145 0 : t <= NS_FRAME_OVERFLOW_DELTA_MAX &&
9146 7 : r <= NS_FRAME_OVERFLOW_DELTA_MAX &&
9147 12 : b <= NS_FRAME_OVERFLOW_DELTA_MAX &&
9148 1 : // we have to check these against zero because we *never* want to
9149 : // set a frame as having no overflow in this function. This is
9150 : // because FinishAndStoreOverflow calls this function prior to
9151 : // SetRect based on whether the overflow areas match aNewSize.
9152 : // In the case where the overflow areas exactly match mRect but
9153 : // do not match aNewSize, we need to store overflow in a property
9154 : // so that our eventual SetRect/SetSize will know that it has to
9155 : // reset our overflow areas.
9156 : (l | t | r | b) != 0) {
9157 6 : VisualDeltas oldDeltas = mOverflow.mVisualDeltas;
9158 1 : // It's a "small" overflow area so we store the deltas for each edge
9159 : // directly in the frame, rather than allocating a separate rect.
9160 : // If they're all zero, that's fine; we're setting things to
9161 : // no-overflow.
9162 : mOverflow.mVisualDeltas.mLeft = l;
9163 0 : mOverflow.mVisualDeltas.mTop = t;
9164 6 : mOverflow.mVisualDeltas.mRight = r;
9165 0 : mOverflow.mVisualDeltas.mBottom = b;
9166 6 : // There was no scrollable overflow before, and there isn't now.
9167 : return oldDeltas != mOverflow.mVisualDeltas;
9168 0 : } else {
9169 : bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) ||
9170 118 : !aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas());
9171 31 :
9172 : // it's a large overflow area that we need to store as a property
9173 : mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
9174 29 : AddProperty(OverflowAreasProperty(), new nsOverflowAreas(aOverflowAreas));
9175 0 : return changed;
9176 29 : }
9177 : }
9178 :
9179 : /**
9180 : * Compute the union of the border boxes of aFrame and its descendants,
9181 : * in aFrame's coordinate space (if aApplyTransform is false) or its
9182 : * post-transform coordinate space (if aApplyTransform is true).
9183 : */
9184 : static nsRect
9185 : UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform,
9186 0 : bool& aOutValid,
9187 : const nsSize* aSizeOverride = nullptr,
9188 : const nsOverflowAreas* aOverflowOverride = nullptr)
9189 : {
9190 : const nsRect bounds(nsPoint(0, 0),
9191 0 : aSizeOverride ? *aSizeOverride : aFrame->GetSize());
9192 0 :
9193 : // The SVG container frames besides SVGTextFrame do not maintain
9194 : // an accurate mRect. It will make the outline be larger than
9195 : // we expect, we need to make them narrow to their children's outline.
9196 : // aOutValid is set to false if the returned nsRect is not valid
9197 : // and should not be included in the outline rectangle.
9198 : aOutValid = !(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
9199 0 : !aFrame->IsFrameOfType(nsIFrame::eSVGContainer) ||
9200 0 : aFrame->IsSVGTextFrame();
9201 0 :
9202 : nsRect u;
9203 0 :
9204 : if (!aFrame->FrameMaintainsOverflow()) {
9205 0 : return u;
9206 : }
9207 :
9208 : // Start from our border-box, transformed. See comment below about
9209 : // transform of children.
9210 : bool doTransform = aApplyTransform && aFrame->IsTransformed();
9211 0 : if (doTransform) {
9212 0 : u = nsDisplayTransform::TransformRect(bounds, aFrame, &bounds);
9213 0 : } else {
9214 : u = bounds;
9215 0 : }
9216 :
9217 : // Only iterate through the children if the overflow areas suggest
9218 : // that we might need to, and if the frame doesn't clip its overflow
9219 : // anyway.
9220 : if (aOverflowOverride) {
9221 0 : if (!doTransform &&
9222 0 : bounds.IsEqualEdges(aOverflowOverride->VisualOverflow()) &&
9223 0 : bounds.IsEqualEdges(aOverflowOverride->ScrollableOverflow())) {
9224 0 : return u;
9225 : }
9226 : } else {
9227 : if (!doTransform &&
9228 0 : bounds.IsEqualEdges(aFrame->GetVisualOverflowRect()) &&
9229 0 : bounds.IsEqualEdges(aFrame->GetScrollableOverflowRect())) {
9230 0 : return u;
9231 : }
9232 : }
9233 : const nsStyleDisplay* disp = aFrame->StyleDisplay();
9234 0 : LayoutFrameType fType = aFrame->Type();
9235 0 : if (nsFrame::ShouldApplyOverflowClipping(aFrame, disp) ||
9236 0 : fType == LayoutFrameType::Scroll ||
9237 0 : fType == LayoutFrameType::ListControl ||
9238 0 : fType == LayoutFrameType::SVGOuterSVG) {
9239 : return u;
9240 : }
9241 :
9242 : const nsStyleEffects* effects = aFrame->StyleEffects();
9243 0 : Maybe<nsRect> clipPropClipRect =
9244 : aFrame->GetClipPropClipRect(disp, effects, bounds.Size());
9245 0 :
9246 : // Iterate over all children except pop-ups.
9247 : const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
9248 : nsIFrame::kSelectPopupList);
9249 0 : for (nsIFrame::ChildListIterator childLists(aFrame);
9250 0 : !childLists.IsDone(); childLists.Next()) {
9251 0 : if (skip.Contains(childLists.CurrentID())) {
9252 0 : continue;
9253 0 : }
9254 :
9255 : nsFrameList children = childLists.CurrentList();
9256 0 : for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
9257 0 : nsIFrame* child = e.get();
9258 0 : // Note that passing |true| for aApplyTransform when
9259 : // child->Combines3DTransformWithAncestors() is incorrect if our
9260 : // aApplyTransform is false... but the opposite would be as
9261 : // well. This is because elements within a preserve-3d scene
9262 : // are always transformed up to the top of the scene. This
9263 : // means we don't have a mechanism for getting a transform up to
9264 : // an intermediate point within the scene. We choose to
9265 : // over-transform rather than under-transform because this is
9266 : // consistent with other overflow areas.
9267 : bool validRect = true;
9268 0 : nsRect childRect = UnionBorderBoxes(child, true, validRect) +
9269 0 : child->GetPosition();
9270 0 :
9271 : if (!validRect) {
9272 0 : continue;
9273 0 : }
9274 :
9275 : if (clipPropClipRect) {
9276 0 : // Intersect with the clip before transforming.
9277 : childRect.IntersectRect(childRect, *clipPropClipRect);
9278 0 : }
9279 :
9280 : // Note that we transform each child separately according to
9281 : // aFrame's transform, and then union, which gives a different
9282 : // (smaller) result from unioning and then transforming the
9283 : // union. This doesn't match the way we handle overflow areas
9284 : // with 2-D transforms, though it does match the way we handle
9285 : // overflow areas in preserve-3d 3-D scenes.
9286 : if (doTransform && !child->Combines3DTransformWithAncestors()) {
9287 0 : childRect = nsDisplayTransform::TransformRect(childRect, aFrame, &bounds);
9288 0 : }
9289 :
9290 : // If a SVGContainer has a non-SVGContainer child, we assign
9291 : // its child's outline to this SVGContainer directly.
9292 : if (!aOutValid && validRect) {
9293 0 : u = childRect;
9294 0 : aOutValid = true;
9295 0 : } else {
9296 : u.UnionRectEdges(u, childRect);
9297 0 : }
9298 : }
9299 : }
9300 :
9301 : return u;
9302 : }
9303 :
9304 : static void
9305 : ComputeAndIncludeOutlineArea(nsIFrame* aFrame, nsOverflowAreas& aOverflowAreas,
9306 720 : const nsSize& aNewSize)
9307 : {
9308 : const nsStyleOutline* outline = aFrame->StyleOutline();
9309 720 : if (!outline->ShouldPaintOutline()) {
9310 720 : return;
9311 0 : }
9312 :
9313 : // When the outline property is set on a :-moz-block-inside-inline-wrapper
9314 : // pseudo-element, it inherited that outline from the inline that was broken
9315 : // because it contained a block. In that case, we don't want a really wide
9316 : // outline if the block inside the inline is narrow, so union the actual
9317 : // contents of the anonymous blocks.
9318 : nsIFrame *frameForArea = aFrame;
9319 : do {
9320 : nsAtom *pseudoType = frameForArea->Style()->GetPseudo();
9321 0 : if (pseudoType != nsCSSAnonBoxes::mozBlockInsideInlineWrapper)
9322 0 : break;
9323 : // If we're done, we really want it and all its later siblings.
9324 : frameForArea = frameForArea->PrincipalChildList().FirstChild();
9325 0 : NS_ASSERTION(frameForArea, "anonymous block with no children?");
9326 0 : } while (frameForArea);
9327 0 :
9328 : // Find the union of the border boxes of all descendants, or in
9329 : // the block-in-inline case, all descendants we care about.
9330 : //
9331 : // Note that the interesting perspective-related cases are taken
9332 : // care of by the code that handles those issues for overflow
9333 : // calling FinishAndStoreOverflow again, which in turn calls this
9334 : // function again. We still need to deal with preserve-3d a bit.
9335 : nsRect innerRect;
9336 0 : bool validRect;
9337 : if (frameForArea == aFrame) {
9338 0 : innerRect = UnionBorderBoxes(aFrame, false, validRect, &aNewSize, &aOverflowAreas);
9339 0 : } else {
9340 : for (; frameForArea; frameForArea = frameForArea->GetNextSibling()) {
9341 0 : nsRect r(UnionBorderBoxes(frameForArea, true, validRect));
9342 0 :
9343 : // Adjust for offsets transforms up to aFrame's pre-transform
9344 : // (i.e., normal) coordinate space; see comments in
9345 : // UnionBorderBoxes for some of the subtlety here.
9346 : for (nsIFrame *f = frameForArea, *parent = f->GetParent();
9347 0 : /* see middle of loop */;
9348 : f = parent, parent = f->GetParent()) {
9349 0 : r += f->GetPosition();
9350 0 : if (parent == aFrame) {
9351 0 : break;
9352 : }
9353 : if (parent->IsTransformed() && !f->Combines3DTransformWithAncestors()) {
9354 0 : r = nsDisplayTransform::TransformRect(r, parent);
9355 0 : }
9356 : }
9357 :
9358 : innerRect.UnionRect(innerRect, r);
9359 0 : }
9360 : }
9361 :
9362 : // Keep this code in sync with GetOutlineInnerRect in nsCSSRendering.cpp.
9363 : aFrame->SetProperty(nsIFrame::OutlineInnerRectProperty(),
9364 : new nsRect(innerRect));
9365 0 : const nscoord offset = outline->mOutlineOffset;
9366 0 : nsRect outerRect(innerRect);
9367 0 : bool useOutlineAuto = false;
9368 0 : if (nsLayoutUtils::IsOutlineStyleAutoEnabled()) {
9369 0 : useOutlineAuto = outline->mOutlineStyle == NS_STYLE_BORDER_STYLE_AUTO;
9370 0 : if (MOZ_UNLIKELY(useOutlineAuto)) {
9371 0 : nsPresContext* presContext = aFrame->PresContext();
9372 0 : nsITheme* theme = presContext->GetTheme();
9373 0 : if (theme && theme->ThemeSupportsWidget(presContext, aFrame,
9374 0 : NS_THEME_FOCUS_OUTLINE)) {
9375 0 : outerRect.Inflate(offset);
9376 0 : theme->GetWidgetOverflow(presContext->DeviceContext(), aFrame,
9377 0 : NS_THEME_FOCUS_OUTLINE, &outerRect);
9378 0 : } else {
9379 : useOutlineAuto = false;
9380 : }
9381 : }
9382 : }
9383 : if (MOZ_LIKELY(!useOutlineAuto)) {
9384 0 : nscoord width = outline->GetOutlineWidth();
9385 0 : outerRect.Inflate(width + offset);
9386 0 : }
9387 :
9388 : nsRect& vo = aOverflowAreas.VisualOverflow();
9389 0 : vo.UnionRectEdges(vo, innerRect.Union(outerRect));
9390 0 : }
9391 :
9392 : bool
9393 : nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
9394 720 : nsSize aNewSize, nsSize* aOldSize,
9395 : const nsStyleDisplay* aStyleDisplay)
9396 : {
9397 : MOZ_ASSERT(FrameMaintainsOverflow(),
9398 0 : "Don't call - overflow rects not maintained on these SVG frames");
9399 :
9400 : const nsStyleDisplay* disp = StyleDisplayWithOptionalParam(aStyleDisplay);
9401 0 : EffectSet* effectSet = EffectSet::GetEffectSet(this);
9402 720 : bool hasTransform = IsTransformed(disp);
9403 0 :
9404 : nsRect bounds(nsPoint(0, 0), aNewSize);
9405 1440 : // Store the passed in overflow area if we are a preserve-3d frame or we have
9406 : // a transform, and it's not just the frame bounds.
9407 : if (hasTransform || Combines3DTransformWithAncestors(disp)) {
9408 720 : if (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
9409 0 : !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) {
9410 7 : nsOverflowAreas* initial =
9411 : GetProperty(nsIFrame::InitialOverflowProperty());
9412 0 : if (!initial) {
9413 0 : AddProperty(nsIFrame::InitialOverflowProperty(),
9414 13 : new nsOverflowAreas(aOverflowAreas));
9415 13 : } else if (initial != &aOverflowAreas) {
9416 0 : *initial = aOverflowAreas;
9417 1 : }
9418 : } else {
9419 : DeleteProperty(nsIFrame::InitialOverflowProperty());
9420 7 : }
9421 : #ifdef DEBUG
9422 : SetProperty(nsIFrame::DebugInitialOverflowPropertyApplied(), true);
9423 31 : #endif
9424 : } else {
9425 : #ifdef DEBUG
9426 : DeleteProperty(nsIFrame::DebugInitialOverflowPropertyApplied());
9427 0 : #endif
9428 : }
9429 :
9430 : // This is now called FinishAndStoreOverflow() instead of
9431 : // StoreOverflow() because frame-generic ways of adding overflow
9432 : // can happen here, e.g. CSS2 outline and native theme.
9433 : // If the overflow area width or height is nscoord_MAX, then a
9434 : // saturating union may have encounted an overflow, so the overflow may not
9435 : // contain the frame border-box. Don't warn in that case.
9436 : // Don't warn for SVG either, since SVG doesn't need the overflow area
9437 : // to contain the frame bounds.
9438 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
9439 0 : DebugOnly<nsRect*> r = &aOverflowAreas.Overflow(otype);
9440 0 : NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 ||
9441 2872 : r->width == nscoord_MAX || r->height == nscoord_MAX ||
9442 : (mState & NS_FRAME_SVG_LAYOUT) ||
9443 : r->Contains(nsRect(nsPoint(0,0), aNewSize)),
9444 : "Computed overflow area must contain frame bounds");
9445 : }
9446 :
9447 : // If we clip our children, clear accumulated overflow area. The
9448 : // children are actually clipped to the padding-box, but since the
9449 : // overflow area should include the entire border-box, just set it to
9450 : // the border-box here.
9451 : NS_ASSERTION((disp->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
9452 0 : (disp->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
9453 : "If one overflow is clip, the other should be too");
9454 : if (nsFrame::ShouldApplyOverflowClipping(this, disp)) {
9455 720 : // The contents are actually clipped to the padding area
9456 : aOverflowAreas.SetAllTo(bounds);
9457 37 : }
9458 :
9459 : // Overflow area must always include the frame's top-left and bottom-right,
9460 : // even if the frame rect is empty (so we can scroll to those positions).
9461 : // Pending a real fix for bug 426879, don't do this for inline frames
9462 : // with zero width.
9463 : // Do not do this for SVG either, since it will usually massively increase
9464 : // the area unnecessarily.
9465 : if ((aNewSize.width != 0 || !IsInlineFrame()) &&
9466 1440 : !(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
9467 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
9468 3340 : nsRect& o = aOverflowAreas.Overflow(otype);
9469 1336 : o.UnionRectEdges(o, bounds);
9470 0 : }
9471 : }
9472 :
9473 : // Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background,
9474 : // so we add theme background overflow here so it's not clipped.
9475 : if (!::IsXULBoxWrapped(this) && IsThemed(disp)) {
9476 0 : nsRect r(bounds);
9477 0 : nsPresContext *presContext = PresContext();
9478 0 : if (presContext->GetTheme()->
9479 0 : GetWidgetOverflow(presContext->DeviceContext(), this,
9480 216 : disp->mAppearance, &r)) {
9481 108 : nsRect& vo = aOverflowAreas.VisualOverflow();
9482 0 : vo.UnionRectEdges(vo, r);
9483 0 : }
9484 : }
9485 :
9486 : ComputeAndIncludeOutlineArea(this, aOverflowAreas, aNewSize);
9487 720 :
9488 : nsSize oldSize = mRect.Size();
9489 0 : bool sizeChanged = ((aOldSize ? *aOldSize : oldSize) != aNewSize);
9490 720 :
9491 : // Our frame size may not have been computed and set yet, but code under
9492 : // functions such as ComputeEffectsRect (which we're about to call) use the
9493 : // values that are stored in our frame rect to compute their results. We
9494 : // need the results from those functions to be based on the frame size that
9495 : // we *will* have, so we temporarily set our frame size here before calling
9496 : // those functions.
9497 : //
9498 : // XXX Someone should document here why we revert the frame size before we
9499 : // return rather than just leaving it set.
9500 : //
9501 : // We pass false here to avoid invalidating display items for this temporary
9502 : // change. We sometimes reflow frames multiple times, with the final size being
9503 : // the same as the initial. The single call to SetSize after reflow is done
9504 : // will take care of invalidating display items if the size has actually
9505 : // changed.
9506 : SetSize(aNewSize, false);
9507 720 :
9508 : // Nothing in here should affect scrollable overflow.
9509 : aOverflowAreas.VisualOverflow() =
9510 1440 : ComputeEffectsRect(this, aOverflowAreas.VisualOverflow(), aNewSize);
9511 1440 :
9512 : // Absolute position clipping
9513 : const nsStyleEffects* effects = StyleEffects();
9514 0 : Maybe<nsRect> clipPropClipRect =
9515 : GetClipPropClipRect(disp, effects, aNewSize);
9516 1440 : if (clipPropClipRect) {
9517 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
9518 0 : nsRect& o = aOverflowAreas.Overflow(otype);
9519 0 : o.IntersectRect(o, *clipPropClipRect);
9520 0 : }
9521 : }
9522 :
9523 : /* If we're transformed, transform the overflow rect by the current transformation. */
9524 : if (ChildrenHavePerspective(disp) && sizeChanged) {
9525 720 : nsRect newBounds(nsPoint(0, 0), aNewSize);
9526 0 : RecomputePerspectiveChildrenOverflow(this);
9527 0 : }
9528 :
9529 : if (hasTransform) {
9530 0 : SetProperty(nsIFrame::PreTransformOverflowAreasProperty(),
9531 : new nsOverflowAreas(aOverflowAreas));
9532 0 :
9533 : if (Combines3DTransformWithAncestors(disp)) {
9534 31 : /* If we're a preserve-3d leaf frame, then our pre-transform overflow should be correct. Our
9535 : * post-transform overflow is empty though, because we only contribute to the overflow area
9536 : * of the preserve-3d root frame.
9537 : * If we're an intermediate frame then the pre-transform overflow should contain all our
9538 : * non-preserve-3d children, which is what we want. Again we have no post-transform overflow.
9539 : */
9540 : aOverflowAreas.SetAllTo(nsRect());
9541 0 : } else {
9542 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
9543 0 : nsRect& o = aOverflowAreas.Overflow(otype);
9544 0 : o = nsDisplayTransform::TransformRect(o, this);
9545 0 : }
9546 :
9547 : /* If we're the root of the 3d context, then we want to include the overflow areas of all
9548 : * the participants. This won't have happened yet as the code above set their overflow
9549 : * area to empty. Manually collect these overflow areas now.
9550 : */
9551 : if (Extend3DContext(disp, effectSet)) {
9552 0 : ComputePreserve3DChildrenOverflow(aOverflowAreas);
9553 0 : }
9554 : }
9555 : } else {
9556 : DeleteProperty(nsIFrame::PreTransformOverflowAreasProperty());
9557 689 : }
9558 :
9559 : /* Revert the size change in case some caller is depending on this. */
9560 : SetSize(oldSize, false);
9561 720 :
9562 : bool anyOverflowChanged;
9563 : if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
9564 720 : anyOverflowChanged = SetOverflowAreas(aOverflowAreas);
9565 58 : } else {
9566 : anyOverflowChanged = ClearOverflowRects();
9567 662 : }
9568 :
9569 : if (anyOverflowChanged) {
9570 720 : SVGObserverUtils::InvalidateDirectRenderingObservers(this);
9571 44 : }
9572 : return anyOverflowChanged;
9573 0 : }
9574 :
9575 : void
9576 : nsIFrame::RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame)
9577 0 : {
9578 : nsIFrame::ChildListIterator lists(this);
9579 0 : for (; !lists.IsDone(); lists.Next()) {
9580 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
9581 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
9582 0 : nsIFrame* child = childFrames.get();
9583 0 : if (!child->FrameMaintainsOverflow()) {
9584 0 : continue; // frame does not maintain overflow rects
9585 : }
9586 : if (child->HasPerspective()) {
9587 0 : nsOverflowAreas* overflow =
9588 : child->GetProperty(nsIFrame::InitialOverflowProperty());
9589 0 : nsRect bounds(nsPoint(0, 0), child->GetSize());
9590 0 : if (overflow) {
9591 0 : nsOverflowAreas overflowCopy = *overflow;
9592 0 : child->FinishAndStoreOverflow(overflowCopy, bounds.Size());
9593 0 : } else {
9594 : nsOverflowAreas boundsOverflow;
9595 0 : boundsOverflow.SetAllTo(bounds);
9596 0 : child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
9597 0 : }
9598 : } else if (child->GetContainingBlock(SKIP_SCROLLED_FRAME) == aStartFrame) {
9599 0 : // If a frame is using perspective, then the size used to compute
9600 : // perspective-origin is the size of the frame belonging to its parent
9601 : // style. We must find any descendant frames using our size
9602 : // (by recursing into frames that have the same containing block)
9603 : // to update their overflow rects too.
9604 : child->RecomputePerspectiveChildrenOverflow(aStartFrame);
9605 0 : }
9606 : }
9607 : }
9608 : }
9609 0 :
9610 : void
9611 : nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas)
9612 0 : {
9613 : // Find all descendants that participate in the 3d context, and include their overflow.
9614 : // These descendants have an empty overflow, so won't have been included in the normal
9615 : // overflow calculation. Any children that don't participate have normal overflow,
9616 : // so will have been included already.
9617 :
9618 : nsRect childVisual;
9619 0 : nsRect childScrollable;
9620 0 : nsIFrame::ChildListIterator lists(this);
9621 0 : for (; !lists.IsDone(); lists.Next()) {
9622 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
9623 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
9624 0 : nsIFrame* child = childFrames.get();
9625 0 :
9626 : // If this child participates in the 3d context, then take the pre-transform
9627 : // region (which contains all descendants that aren't participating in the 3d context)
9628 : // and transform it into the 3d context root coordinate space.
9629 : const nsStyleDisplay* childDisp = child->StyleDisplay();
9630 0 : if (child->Combines3DTransformWithAncestors(childDisp)) {
9631 0 : nsOverflowAreas childOverflow = child->GetOverflowAreasRelativeToSelf();
9632 0 :
9633 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
9634 0 : nsRect& o = childOverflow.Overflow(otype);
9635 0 : o = nsDisplayTransform::TransformRect(o, child);
9636 0 : }
9637 :
9638 : aOverflowAreas.UnionWith(childOverflow);
9639 0 :
9640 : // If this child also extends the 3d context, then recurse into it
9641 : // looking for more participants.
9642 : if (child->Extend3DContext(childDisp)) {
9643 0 : child->ComputePreserve3DChildrenOverflow(aOverflowAreas);
9644 0 : }
9645 : }
9646 : }
9647 : }
9648 : }
9649 0 :
9650 : uint32_t
9651 : nsIFrame::GetDepthInFrameTree() const
9652 0 : {
9653 : uint32_t result = 0;
9654 0 : for (nsContainerFrame* ancestor = GetParent(); ancestor;
9655 0 : ancestor = ancestor->GetParent()) {
9656 0 : result++;
9657 0 : }
9658 : return result;
9659 0 : }
9660 :
9661 : void
9662 : nsFrame::ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
9663 68 : nsIFrame* aChildFrame)
9664 : {
9665 : aOverflowAreas.UnionWith(aChildFrame->GetOverflowAreas() +
9666 204 : aChildFrame->GetPosition());
9667 0 : }
9668 68 :
9669 : bool
9670 : nsFrame::ShouldAvoidBreakInside(const ReflowInput& aReflowInput) const
9671 0 : {
9672 : const auto* disp = StyleDisplay();
9673 0 : return !aReflowInput.mFlags.mIsTopOfPage &&
9674 0 : NS_STYLE_PAGE_BREAK_AVOID == disp->mBreakInside &&
9675 0 : !(HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) && IsAbsolutelyPositioned(disp)) &&
9676 0 : !GetPrevInFlow();
9677 0 : }
9678 :
9679 : /**
9680 : * This function takes a frame that is part of a block-in-inline split,
9681 : * and _if_ that frame is an anonymous block created by an ib split it
9682 : * returns the block's preceding inline. This is needed because the
9683 : * split inline's style is the parent of the anonymous block's style.
9684 : *
9685 : * If aFrame is not an anonymous block, null is returned.
9686 : */
9687 : static nsIFrame*
9688 : GetIBSplitSiblingForAnonymousBlock(const nsIFrame* aFrame)
9689 0 : {
9690 : MOZ_ASSERT(aFrame, "Must have a non-null frame!");
9691 0 : NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT,
9692 0 : "GetIBSplitSibling should only be called on ib-split frames");
9693 :
9694 : nsAtom* type = aFrame->Style()->GetPseudo();
9695 0 : if (type != nsCSSAnonBoxes::mozBlockInsideInlineWrapper) {
9696 0 : // it's not an anonymous block
9697 : return nullptr;
9698 : }
9699 :
9700 : // Find the first continuation of the frame. (Ugh. This ends up
9701 : // being O(N^2) when it is called O(N) times.)
9702 : aFrame = aFrame->FirstContinuation();
9703 0 :
9704 : /*
9705 : * Now look up the nsGkAtoms::IBSplitPrevSibling
9706 : * property.
9707 : */
9708 : nsIFrame *ibSplitSibling =
9709 : aFrame->GetProperty(nsIFrame::IBSplitPrevSibling());
9710 0 : NS_ASSERTION(ibSplitSibling, "Broken frame tree?");
9711 0 : return ibSplitSibling;
9712 : }
9713 :
9714 : /**
9715 : * Get the parent, corrected for the mangled frame tree resulting from
9716 : * having a block within an inline. The result only differs from the
9717 : * result of |GetParent| when |GetParent| returns an anonymous block
9718 : * that was created for an element that was 'display: inline' because
9719 : * that element contained a block.
9720 : *
9721 : * Also skip anonymous scrolled-content parents; inherit directly from the
9722 : * outer scroll frame.
9723 : *
9724 : * Also skip NAC parents if the child frame is NAC.
9725 : */
9726 : static nsIFrame*
9727 : GetCorrectedParent(const nsIFrame* aFrame)
9728 0 : {
9729 : nsIFrame* parent = aFrame->GetParent();
9730 0 : if (!parent) {
9731 0 : return nullptr;
9732 : }
9733 :
9734 : // For a table caption we want the _inner_ table frame (unless it's anonymous)
9735 : // as the style parent.
9736 : if (aFrame->IsTableCaption()) {
9737 0 : nsIFrame* innerTable = parent->PrincipalChildList().FirstChild();
9738 0 : if (!innerTable->Style()->GetPseudo()) {
9739 0 : return innerTable;
9740 : }
9741 : }
9742 :
9743 : // Table wrappers are always anon boxes; if we're in here for an outer
9744 : // table, that actually means its the _inner_ table that wants to
9745 : // know its parent. So get the pseudo of the inner in that case.
9746 : nsAtom* pseudo = aFrame->Style()->GetPseudo();
9747 0 : if (pseudo == nsCSSAnonBoxes::tableWrapper) {
9748 0 : pseudo = aFrame->PrincipalChildList().FirstChild()->Style()->GetPseudo();
9749 0 : }
9750 :
9751 : // Prevent a NAC pseudo-element from inheriting from its NAC parent, and
9752 : // inherit from the NAC generator element instead.
9753 : if (pseudo) {
9754 0 : MOZ_ASSERT(aFrame->GetContent());
9755 0 : Element* element = Element::FromNode(aFrame->GetContent());
9756 0 : // Make sure to avoid doing the fixup for non-element-backed pseudos like
9757 : // ::first-line and such.
9758 : if (element &&
9759 0 : !element->IsRootOfNativeAnonymousSubtree() &&
9760 0 : element->GetPseudoElementType() == aFrame->Style()->GetPseudoType()) {
9761 0 : while (parent->GetContent() &&
9762 0 : !parent->GetContent()->IsRootOfAnonymousSubtree()) {
9763 0 : parent = parent->GetInFlowParent();
9764 0 : }
9765 : parent = parent->GetInFlowParent();
9766 0 : }
9767 : }
9768 :
9769 : return nsFrame::CorrectStyleParentFrame(parent, pseudo);
9770 0 : }
9771 :
9772 : /* static */
9773 : nsIFrame*
9774 : nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
9775 171 : nsAtom* aChildPseudo)
9776 : {
9777 : MOZ_ASSERT(aProspectiveParent, "Must have a prospective parent");
9778 171 :
9779 : if (aChildPseudo) {
9780 171 : // Non-inheriting anon boxes have no style parent frame at all.
9781 : if (nsCSSAnonBoxes::IsNonInheritingAnonBox(aChildPseudo)) {
9782 0 : return nullptr;
9783 : }
9784 :
9785 : // Other anon boxes are parented to their actual parent already, except
9786 : // for non-elements. Those should not be treated as an anon box.
9787 : if (!nsCSSAnonBoxes::IsNonElement(aChildPseudo) &&
9788 0 : nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) {
9789 0 : NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozBlockInsideInlineWrapper,
9790 0 : "Should have dealt with kids that have "
9791 : "NS_FRAME_PART_OF_IBSPLIT elsewhere");
9792 : return aProspectiveParent;
9793 : }
9794 : }
9795 :
9796 : // Otherwise, walk up out of all anon boxes. For placeholder frames, walk out
9797 : // of all pseudo-elements as well. Otherwise ReparentComputedStyle could cause
9798 : // style data to be out of sync with the frame tree.
9799 : nsIFrame* parent = aProspectiveParent;
9800 : do {
9801 : if (parent->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
9802 392 : nsIFrame* sibling = GetIBSplitSiblingForAnonymousBlock(parent);
9803 0 :
9804 : if (sibling) {
9805 0 : // |parent| was a block in an {ib} split; use the inline as
9806 : // |the style parent.
9807 : parent = sibling;
9808 0 : }
9809 : }
9810 :
9811 : nsAtom* parentPseudo = parent->Style()->GetPseudo();
9812 392 : if (!parentPseudo ||
9813 422 : (!nsCSSAnonBoxes::IsAnonBox(parentPseudo) &&
9814 35 : // nsPlaceholderFrame pases in nsGkAtoms::placeholderFrame for
9815 : // aChildPseudo (even though that's not a valid pseudo-type) just to
9816 : // trigger this behavior of walking up to the nearest non-pseudo
9817 : // ancestor.
9818 : aChildPseudo != nsGkAtoms::placeholderFrame)) {
9819 5 : return parent;
9820 : }
9821 :
9822 : parent = parent->GetInFlowParent();
9823 0 : } while (parent);
9824 1 :
9825 : if (aProspectiveParent->Style()->GetPseudo() ==
9826 0 : nsCSSAnonBoxes::viewportScroll) {
9827 : // aProspectiveParent is the scrollframe for a viewport
9828 : // and the kids are the anonymous scrollbars
9829 : return aProspectiveParent;
9830 : }
9831 :
9832 : // We can get here if the root element is absolutely positioned.
9833 : // We can't test for this very accurately, but it can only happen
9834 : // when the prospective parent is a canvas frame.
9835 : NS_ASSERTION(aProspectiveParent->IsCanvasFrame(),
9836 0 : "Should have found a parent before this");
9837 : return nullptr;
9838 : }
9839 :
9840 : ComputedStyle*
9841 : nsFrame::DoGetParentComputedStyle(nsIFrame** aProviderFrame) const
9842 0 : {
9843 : *aProviderFrame = nullptr;
9844 0 :
9845 : // Handle display:contents and the root frame, when there's no parent frame
9846 : // to inherit from.
9847 : if (MOZ_LIKELY(mContent)) {
9848 38 : Element* parentElement = mContent->GetFlattenedTreeParentElement();
9849 19 : if (MOZ_LIKELY(parentElement)) {
9850 0 : nsAtom* pseudo = Style()->GetPseudo();
9851 0 : if (!pseudo || !mContent->IsElement() ||
9852 0 : (!nsCSSAnonBoxes::IsAnonBox(pseudo) &&
9853 0 : // Ensure that we don't return the display:contents style
9854 : // of the parent content for pseudos that have the same content
9855 : // as their primary frame (like -moz-list-bullets do):
9856 : IsPrimaryFrame()) ||
9857 0 : /* if next is true then it's really a request for the table frame's
9858 : parent context, see nsTable[Outer]Frame::GetParentComputedStyle. */
9859 : pseudo == nsCSSAnonBoxes::tableWrapper) {
9860 0 : if (Servo_Element_IsDisplayContents(parentElement)) {
9861 0 : RefPtr<ComputedStyle> style =
9862 : PresShell()->StyleSet()->ResolveServoStyle(parentElement);
9863 0 : // NOTE(emilio): we return a weak reference because the element also
9864 : // holds the style context alive. This is a bit silly (we could've
9865 : // returned a weak ref directly), but it's probably not worth
9866 : // optimizing, given this function has just one caller which is rare,
9867 : // and this path is rare itself.
9868 : return style;
9869 0 : }
9870 : }
9871 : } else {
9872 : if (!Style()->GetPseudo()) {
9873 57 : // We're a frame for the root. We have no style parent.
9874 : return nullptr;
9875 : }
9876 : }
9877 : }
9878 :
9879 : if (!(mState & NS_FRAME_OUT_OF_FLOW)) {
9880 0 : /*
9881 : * If this frame is an anonymous block created when an inline with a block
9882 : * inside it got split, then the parent style is on its preceding inline. We
9883 : * can get to it using GetIBSplitSiblingForAnonymousBlock.
9884 : */
9885 : if (mState & NS_FRAME_PART_OF_IBSPLIT) {
9886 0 : nsIFrame* ibSplitSibling = GetIBSplitSiblingForAnonymousBlock(this);
9887 0 : if (ibSplitSibling) {
9888 0 : return (*aProviderFrame = ibSplitSibling)->Style();
9889 0 : }
9890 : }
9891 :
9892 : // If this frame is one of the blocks that split an inline, we must
9893 : // return the "special" inline parent, i.e., the parent that this
9894 : // frame would have if we didn't mangle the frame structure.
9895 : *aProviderFrame = GetCorrectedParent(this);
9896 0 : return *aProviderFrame ? (*aProviderFrame)->Style() : nullptr;
9897 0 : }
9898 :
9899 : // We're an out-of-flow frame. For out-of-flow frames, we must
9900 : // resolve underneath the placeholder's parent. The placeholder is
9901 : // reached from the first-in-flow.
9902 : nsPlaceholderFrame* placeholder = FirstInFlow()->GetPlaceholderFrame();
9903 0 : if (!placeholder) {
9904 0 : NS_NOTREACHED("no placeholder frame for out-of-flow frame");
9905 0 : *aProviderFrame = GetCorrectedParent(this);
9906 0 : return *aProviderFrame ? (*aProviderFrame)->Style() : nullptr;
9907 0 : }
9908 : return placeholder->GetParentComputedStyleForOutOfFlow(aProviderFrame);
9909 0 : }
9910 :
9911 : void
9912 : nsFrame::GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
9913 0 : {
9914 : if (!aFrame || !*aFrame)
9915 0 : return;
9916 : nsIFrame *child = *aFrame;
9917 : //if we are a block frame then go for the last line of 'this'
9918 : while (1){
9919 : child = child->PrincipalChildList().FirstChild();
9920 0 : if (!child)
9921 0 : return;//nothing to do
9922 : nsIFrame* siblingFrame;
9923 : nsIContent* content;
9924 : //ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
9925 : //see bug 278197 comment #12 #13 for details
9926 : while ((siblingFrame = child->GetNextSibling()) &&
9927 0 : (content = siblingFrame->GetContent()) &&
9928 0 : !content->IsRootOfNativeAnonymousSubtree())
9929 0 : child = siblingFrame;
9930 : *aFrame = child;
9931 0 : }
9932 0 : }
9933 :
9934 : void
9935 : nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
9936 0 : {
9937 : if (!aFrame || !*aFrame)
9938 0 : return;
9939 : nsIFrame *child = *aFrame;
9940 : while (1){
9941 : child = child->PrincipalChildList().FirstChild();
9942 0 : if (!child)
9943 0 : return;//nothing to do
9944 : *aFrame = child;
9945 0 : }
9946 : }
9947 :
9948 : /* virtual */ bool
9949 : nsIFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
9950 0 : {
9951 : int32_t tabIndex = -1;
9952 2 : if (aTabIndex) {
9953 2 : *aTabIndex = -1; // Default for early return is not focusable
9954 0 : }
9955 : bool isFocusable = false;
9956 2 :
9957 : if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors() &&
9958 0 : Style()->GetPseudo() != nsCSSAnonBoxes::anonymousFlexItem &&
9959 0 : Style()->GetPseudo() != nsCSSAnonBoxes::anonymousGridItem) {
9960 4 : const nsStyleUserInterface* ui = StyleUserInterface();
9961 2 : if (ui->mUserFocus != StyleUserFocus::Ignore &&
9962 2 : ui->mUserFocus != StyleUserFocus::None) {
9963 : // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
9964 : tabIndex = 0;
9965 0 : }
9966 : isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
9967 1 : if (!isFocusable && !aWithMouse && IsScrollFrame() &&
9968 1 : mContent->IsHTMLElement() &&
9969 0 : !mContent->IsRootOfNativeAnonymousSubtree() && mContent->GetParent() &&
9970 2 : !mContent->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
9971 0 : // Elements with scrollable view are focusable with script & tabbable
9972 : // Otherwise you couldn't scroll them with keyboard, which is
9973 : // an accessibility issue (e.g. Section 508 rules)
9974 : // However, we don't make them to be focusable with the mouse,
9975 : // because the extra focus outlines are considered unnecessarily ugly.
9976 : // When clicked on, the selection position within the element
9977 : // will be enough to make them keyboard scrollable.
9978 : nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
9979 0 : if (scrollFrame &&
9980 0 : !scrollFrame->GetScrollbarStyles().IsHiddenInBothDirections() &&
9981 0 : !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
9982 0 : // Scroll bars will be used for overflow
9983 : isFocusable = true;
9984 0 : tabIndex = 0;
9985 0 : }
9986 : }
9987 : }
9988 :
9989 : if (aTabIndex) {
9990 0 : *aTabIndex = tabIndex;
9991 0 : }
9992 : return isFocusable;
9993 0 : }
9994 :
9995 : /**
9996 : * @return true if this text frame ends with a newline character which is
9997 : * treated as preformatted. It should return false if this is not a text frame.
9998 : */
9999 : bool
10000 : nsIFrame::HasSignificantTerminalNewline() const
10001 0 : {
10002 : return false;
10003 0 : }
10004 :
10005 : static uint8_t
10006 : ConvertSVGDominantBaselineToVerticalAlign(uint8_t aDominantBaseline)
10007 0 : {
10008 : // Most of these are approximate mappings.
10009 : switch (aDominantBaseline) {
10010 0 : case NS_STYLE_DOMINANT_BASELINE_HANGING:
10011 : case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE:
10012 : return NS_STYLE_VERTICAL_ALIGN_TEXT_TOP;
10013 : case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE:
10014 : case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
10015 : return NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM;
10016 0 : case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
10017 : case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
10018 : case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL:
10019 : return NS_STYLE_VERTICAL_ALIGN_MIDDLE;
10020 0 : case NS_STYLE_DOMINANT_BASELINE_AUTO:
10021 : case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC:
10022 : return NS_STYLE_VERTICAL_ALIGN_BASELINE;
10023 0 : case NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT:
10024 : case NS_STYLE_DOMINANT_BASELINE_NO_CHANGE:
10025 : case NS_STYLE_DOMINANT_BASELINE_RESET_SIZE:
10026 : // These three should not simply map to 'baseline', but we don't
10027 : // support the complex baseline model that SVG 1.1 has and which
10028 : // css3-linebox now defines.
10029 : return NS_STYLE_VERTICAL_ALIGN_BASELINE;
10030 0 : default:
10031 : NS_NOTREACHED("unexpected aDominantBaseline value");
10032 0 : return NS_STYLE_VERTICAL_ALIGN_BASELINE;
10033 0 : }
10034 : }
10035 :
10036 : uint8_t
10037 : nsIFrame::VerticalAlignEnum() const
10038 23 : {
10039 : if (nsSVGUtils::IsInSVGTextSubtree(this)) {
10040 23 : uint8_t dominantBaseline;
10041 : for (const nsIFrame* frame = this; frame; frame = frame->GetParent()) {
10042 0 : dominantBaseline = frame->StyleSVGReset()->mDominantBaseline;
10043 0 : if (dominantBaseline != NS_STYLE_DOMINANT_BASELINE_AUTO ||
10044 0 : frame->IsSVGTextFrame()) {
10045 0 : break;
10046 : }
10047 : }
10048 : return ConvertSVGDominantBaselineToVerticalAlign(dominantBaseline);
10049 0 : }
10050 :
10051 : const nsStyleCoord& verticalAlign = StyleDisplay()->mVerticalAlign;
10052 0 : if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
10053 0 : return verticalAlign.GetIntValue();
10054 23 : }
10055 :
10056 : return eInvalidVerticalAlign;
10057 : }
10058 :
10059 : /* static */
10060 : void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
10061 0 : nsIFrame::Cursor& aCursor)
10062 : {
10063 : aCursor.mCursor = ui->mCursor;
10064 0 : aCursor.mHaveHotspot = false;
10065 0 : aCursor.mLoading = false;
10066 0 : aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
10067 0 :
10068 : for (const nsCursorImage& item : ui->mCursorImages) {
10069 0 : uint32_t status;
10070 : imgRequestProxy* req = item.GetImage();
10071 0 : if (!req || NS_FAILED(req->GetImageStatus(&status))) {
10072 0 : continue;
10073 0 : }
10074 : if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
10075 0 : // If we are falling back because any cursor before is loading,
10076 : // let the consumer know.
10077 : aCursor.mLoading = true;
10078 0 : } else if (!(status & imgIRequest::STATUS_ERROR)) {
10079 0 : // This is the one we want
10080 : req->GetImage(getter_AddRefs(aCursor.mContainer));
10081 0 : aCursor.mHaveHotspot = item.mHaveHotspot;
10082 0 : aCursor.mHotspotX = item.mHotspotX;
10083 0 : aCursor.mHotspotY = item.mHotspotY;
10084 0 : break;
10085 0 : }
10086 : }
10087 : }
10088 0 :
10089 : NS_IMETHODIMP
10090 : nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
10091 34 : {
10092 : // XXXbz this comment needs some rewriting to make sense in the
10093 : // post-reflow-branch world.
10094 :
10095 : // Ok we need to compute our minimum, preferred, and maximum sizes.
10096 : // 1) Maximum size. This is easy. Its infinite unless it is overloaded by CSS.
10097 : // 2) Preferred size. This is a little harder. This is the size the block would be
10098 : // if it were laid out on an infinite canvas. So we can get this by reflowing
10099 : // the block with and INTRINSIC width and height. We can also do a nice optimization
10100 : // for incremental reflow. If the reflow is incremental then we can pass a flag to
10101 : // have the block compute the preferred width for us! Preferred height can just be
10102 : // the minimum height;
10103 : // 3) Minimum size. This is a toughy. We can pass the block a flag asking for the max element
10104 : // size. That would give us the width. Unfortunately you can only ask for a maxElementSize
10105 : // during an incremental reflow. So on other reflows we will just have to use 0.
10106 : // The min height on the other hand is fairly easy we need to get the largest
10107 : // line height. This can be done with the line iterator.
10108 :
10109 : // if we do have a rendering context
10110 : gfxContext* rendContext = aState.GetRenderingContext();
10111 0 : if (rendContext) {
10112 34 : nsPresContext* presContext = aState.PresContext();
10113 34 :
10114 : // If we don't have any HTML constraints and it's a resize, then nothing in the block
10115 : // could have changed, so no refresh is necessary.
10116 : nsBoxLayoutMetrics* metrics = BoxMetrics();
10117 34 : if (!DoesNeedRecalc(metrics->mBlockPrefSize))
10118 34 : return NS_OK;
10119 4 :
10120 : // the rect we plan to size to.
10121 : nsRect rect = GetRect();
10122 90 :
10123 : nsMargin bp(0,0,0,0);
10124 30 : GetXULBorderAndPadding(bp);
10125 30 :
10126 : {
10127 : // If we're a container for font size inflation, then shrink
10128 : // wrapping inside of us should not apply font size inflation.
10129 : AutoMaybeDisableFontInflation an(this);
10130 60 :
10131 : metrics->mBlockPrefSize.width =
10132 30 : GetPrefISize(rendContext) + bp.LeftRight();
10133 0 : metrics->mBlockMinSize.width =
10134 0 : GetMinISize(rendContext) + bp.LeftRight();
10135 0 : }
10136 :
10137 : // do the nasty.
10138 : const WritingMode wm = aState.OuterReflowInput() ?
10139 30 : aState.OuterReflowInput()->GetWritingMode() : GetWritingMode();
10140 1 : ReflowOutput desiredSize(wm);
10141 1 : BoxReflow(aState, presContext, desiredSize, rendContext,
10142 30 : rect.x, rect.y,
10143 : metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE);
10144 1 :
10145 : metrics->mBlockMinSize.height = 0;
10146 1 : // ok we need the max ascent of the items on the line. So to do this
10147 : // ask the block for its line iterator. Get the max ascent.
10148 : nsAutoLineIterator lines = GetLineIterator();
10149 90 : if (lines)
10150 0 : {
10151 : metrics->mBlockMinSize.height = 0;
10152 4 : int count = 0;
10153 0 : nsIFrame* firstFrame = nullptr;
10154 4 : int32_t framesOnLine;
10155 : nsRect lineBounds;
10156 8 :
10157 : do {
10158 : lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds);
10159 7 :
10160 : if (lineBounds.height > metrics->mBlockMinSize.height)
10161 7 : metrics->mBlockMinSize.height = lineBounds.height;
10162 1 :
10163 : count++;
10164 7 : } while(firstFrame);
10165 7 : } else {
10166 : metrics->mBlockMinSize.height = desiredSize.Height();
10167 26 : }
10168 :
10169 : metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height;
10170 30 :
10171 : if (desiredSize.BlockStartAscent() ==
10172 30 : ReflowOutput::ASK_FOR_BASELINE) {
10173 : if (!nsLayoutUtils::GetFirstLineBaseline(wm, this,
10174 0 : &metrics->mBlockAscent))
10175 : metrics->mBlockAscent = GetLogicalBaseline(wm);
10176 28 : } else {
10177 : metrics->mBlockAscent = desiredSize.BlockStartAscent();
10178 1 : }
10179 :
10180 : #ifdef DEBUG_adaptor
10181 : printf("min=(%d,%d), pref=(%d,%d), ascent=%d\n", metrics->mBlockMinSize.width,
10182 : metrics->mBlockMinSize.height,
10183 : metrics->mBlockPrefSize.width,
10184 : metrics->mBlockPrefSize.height,
10185 : metrics->mBlockAscent);
10186 : #endif
10187 : }
10188 :
10189 : return NS_OK;
10190 : }
10191 :
10192 : /* virtual */ nsILineIterator*
10193 : nsFrame::GetLineIterator()
10194 0 : {
10195 : return nullptr;
10196 0 : }
10197 :
10198 : nsSize
10199 : nsFrame::GetXULPrefSize(nsBoxLayoutState& aState)
10200 18 : {
10201 : nsSize size(0,0);
10202 0 : DISPLAY_PREF_SIZE(this, size);
10203 0 : // If the size is cached, and there are no HTML constraints that we might
10204 : // be depending on, then we just return the cached size.
10205 : nsBoxLayoutMetrics *metrics = BoxMetrics();
10206 0 : if (!DoesNeedRecalc(metrics->mPrefSize)) {
10207 18 : size = metrics->mPrefSize;
10208 0 : return size;
10209 12 : }
10210 :
10211 : if (IsXULCollapsed())
10212 0 : return size;
10213 0 :
10214 : // get our size in CSS.
10215 : bool widthSet, heightSet;
10216 : bool completelyRedefined = nsIFrame::AddXULPrefSize(this, size, widthSet, heightSet);
10217 6 :
10218 : // Refresh our caches with new sizes.
10219 : if (!completelyRedefined) {
10220 6 : RefreshSizeCache(aState);
10221 0 : nsSize blockSize = metrics->mBlockPrefSize;
10222 6 :
10223 : // notice we don't need to add our borders or padding
10224 : // in. That's because the block did it for us.
10225 : if (!widthSet)
10226 0 : size.width = blockSize.width;
10227 0 : if (!heightSet)
10228 6 : size.height = blockSize.height;
10229 0 : }
10230 :
10231 : metrics->mPrefSize = size;
10232 0 : return size;
10233 6 : }
10234 :
10235 : nsSize
10236 : nsFrame::GetXULMinSize(nsBoxLayoutState& aState)
10237 19 : {
10238 : nsSize size(0,0);
10239 19 : DISPLAY_MIN_SIZE(this, size);
10240 0 : // Don't use the cache if we have HTMLReflowInput constraints --- they might have changed
10241 : nsBoxLayoutMetrics *metrics = BoxMetrics();
10242 19 : if (!DoesNeedRecalc(metrics->mMinSize)) {
10243 19 : size = metrics->mMinSize;
10244 14 : return size;
10245 14 : }
10246 :
10247 : if (IsXULCollapsed())
10248 5 : return size;
10249 0 :
10250 : // get our size in CSS.
10251 : bool widthSet, heightSet;
10252 : bool completelyRedefined =
10253 : nsIFrame::AddXULMinSize(aState, this, size, widthSet, heightSet);
10254 5 :
10255 : // Refresh our caches with new sizes.
10256 : if (!completelyRedefined) {
10257 5 : RefreshSizeCache(aState);
10258 0 : nsSize blockSize = metrics->mBlockMinSize;
10259 4 :
10260 : if (!widthSet)
10261 4 : size.width = blockSize.width;
10262 0 : if (!heightSet)
10263 4 : size.height = blockSize.height;
10264 0 : }
10265 :
10266 : metrics->mMinSize = size;
10267 5 : return size;
10268 0 : }
10269 :
10270 : nsSize
10271 : nsFrame::GetXULMaxSize(nsBoxLayoutState& aState)
10272 19 : {
10273 : nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
10274 0 : DISPLAY_MAX_SIZE(this, size);
10275 0 : // Don't use the cache if we have HTMLReflowInput constraints --- they might have changed
10276 : nsBoxLayoutMetrics *metrics = BoxMetrics();
10277 19 : if (!DoesNeedRecalc(metrics->mMaxSize)) {
10278 19 : size = metrics->mMaxSize;
10279 0 : return size;
10280 13 : }
10281 :
10282 : if (IsXULCollapsed())
10283 0 : return size;
10284 0 :
10285 : size = nsBox::GetXULMaxSize(aState);
10286 6 : metrics->mMaxSize = size;
10287 6 :
10288 : return size;
10289 0 : }
10290 :
10291 : nscoord
10292 : nsFrame::GetXULFlex()
10293 96 : {
10294 : nsBoxLayoutMetrics *metrics = BoxMetrics();
10295 0 : if (!DoesNeedRecalc(metrics->mFlex))
10296 96 : return metrics->mFlex;
10297 67 :
10298 : metrics->mFlex = nsBox::GetXULFlex();
10299 0 :
10300 : return metrics->mFlex;
10301 0 : }
10302 :
10303 : nscoord
10304 : nsFrame::GetXULBoxAscent(nsBoxLayoutState& aState)
10305 0 : {
10306 : nsBoxLayoutMetrics *metrics = BoxMetrics();
10307 0 : if (!DoesNeedRecalc(metrics->mAscent))
10308 145 : return metrics->mAscent;
10309 121 :
10310 : if (IsXULCollapsed()) {
10311 0 : metrics->mAscent = 0;
10312 0 : } else {
10313 : // Refresh our caches with new sizes.
10314 : RefreshSizeCache(aState);
10315 24 : metrics->mAscent = metrics->mBlockAscent;
10316 0 : }
10317 :
10318 : return metrics->mAscent;
10319 0 : }
10320 :
10321 : nsresult
10322 : nsFrame::DoXULLayout(nsBoxLayoutState& aState)
10323 0 : {
10324 : nsRect ourRect(mRect);
10325 0 :
10326 : gfxContext* rendContext = aState.GetRenderingContext();
10327 36 : nsPresContext* presContext = aState.PresContext();
10328 36 : WritingMode ourWM = GetWritingMode();
10329 0 : const WritingMode outerWM = aState.OuterReflowInput() ?
10330 0 : aState.OuterReflowInput()->GetWritingMode() : ourWM;
10331 36 : ReflowOutput desiredSize(outerWM);
10332 72 : LogicalSize ourSize = GetLogicalSize(outerWM);
10333 36 :
10334 : if (rendContext) {
10335 36 :
10336 : BoxReflow(aState, presContext, desiredSize, rendContext,
10337 0 : ourRect.x, ourRect.y, ourRect.width, ourRect.height);
10338 36 :
10339 : if (IsXULCollapsed()) {
10340 0 : SetSize(nsSize(0, 0));
10341 0 : } else {
10342 :
10343 : // if our child needs to be bigger. This might happend with
10344 : // wrapping text. There is no way to predict its height until we
10345 : // reflow it. Now that we know the height reshuffle upward.
10346 : if (desiredSize.ISize(outerWM) > ourSize.ISize(outerWM) ||
10347 72 : desiredSize.BSize(outerWM) > ourSize.BSize(outerWM)) {
10348 0 :
10349 : #ifdef DEBUG_GROW
10350 : XULDumpBox(stdout);
10351 : printf(" GREW from (%d,%d) -> (%d,%d)\n",
10352 : ourSize.ISize(outerWM), ourSize.BSize(outerWM),
10353 : desiredSize.ISize(outerWM), desiredSize.BSize(outerWM));
10354 : #endif
10355 :
10356 : if (desiredSize.ISize(outerWM) > ourSize.ISize(outerWM)) {
10357 0 : ourSize.ISize(outerWM) = desiredSize.ISize(outerWM);
10358 0 : }
10359 :
10360 : if (desiredSize.BSize(outerWM) > ourSize.BSize(outerWM)) {
10361 0 : ourSize.BSize(outerWM) = desiredSize.BSize(outerWM);
10362 1 : }
10363 : }
10364 :
10365 : // ensure our size is what we think is should be. Someone could have
10366 : // reset the frame to be smaller or something dumb like that.
10367 : SetSize(ourSize.ConvertTo(ourWM, outerWM));
10368 36 : }
10369 : }
10370 :
10371 : // Should we do this if IsXULCollapsed() is true?
10372 : LogicalSize size(GetLogicalSize(outerWM));
10373 0 : desiredSize.ISize(outerWM) = size.ISize(outerWM);
10374 0 : desiredSize.BSize(outerWM) = size.BSize(outerWM);
10375 36 : desiredSize.UnionOverflowAreasWithDesiredBounds();
10376 36 :
10377 : if (HasAbsolutelyPositionedChildren()) {
10378 0 : // Set up a |reflowInput| to pass into ReflowAbsoluteFrames
10379 : ReflowInput reflowInput(aState.PresContext(), this,
10380 : aState.GetRenderingContext(),
10381 : LogicalSize(ourWM, ISize(),
10382 0 : NS_UNCONSTRAINEDSIZE),
10383 : ReflowInput::DUMMY_PARENT_REFLOW_STATE);
10384 0 :
10385 : AddStateBits(NS_FRAME_IN_REFLOW);
10386 0 : // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
10387 : // (just a dummy value; hopefully that's OK)
10388 : nsReflowStatus reflowStatus;
10389 0 : ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
10390 0 : reflowInput, reflowStatus);
10391 0 : RemoveStateBits(NS_FRAME_IN_REFLOW);
10392 0 : }
10393 :
10394 : nsSize oldSize(ourRect.Size());
10395 0 : FinishAndStoreOverflow(desiredSize.mOverflowAreas,
10396 36 : size.GetPhysicalSize(outerWM), &oldSize);
10397 0 :
10398 : SyncLayout(aState);
10399 0 :
10400 : return NS_OK;
10401 72 : }
10402 :
10403 : void
10404 : nsFrame::BoxReflow(nsBoxLayoutState& aState,
10405 66 : nsPresContext* aPresContext,
10406 : ReflowOutput& aDesiredSize,
10407 : gfxContext* aRenderingContext,
10408 : nscoord aX,
10409 : nscoord aY,
10410 : nscoord aWidth,
10411 : nscoord aHeight,
10412 : bool aMoveFrame)
10413 : {
10414 : DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor");
10415 66 :
10416 : #ifdef DEBUG_REFLOW
10417 : nsAdaptorAddIndents();
10418 : printf("Reflowing: ");
10419 : nsFrame::ListTag(stdout, mFrame);
10420 : printf("\n");
10421 : gIndent2++;
10422 : #endif
10423 :
10424 : nsBoxLayoutMetrics* metrics = BoxMetrics();
10425 66 : if (MOZ_UNLIKELY(!metrics)) {
10426 66 : // Can't proceed without BoxMetrics. This should only happen if something
10427 : // is seriously broken, e.g. if we try to do XUL layout on a non-XUL frame.
10428 : // (If this is a content process, we'll abort even in release builds,
10429 : // because XUL layout mixup is extra surprising in content, and aborts are
10430 : // less catastrophic in content vs. in chrome.)
10431 : MOZ_RELEASE_ASSERT(!XRE_IsContentProcess(),
10432 0 : "Starting XUL BoxReflow w/o BoxMetrics (in content)?");
10433 : MOZ_ASSERT_UNREACHABLE("Starting XUL BoxReflow w/o BoxMetrics?");
10434 0 : return;
10435 : }
10436 :
10437 : nsReflowStatus status;
10438 0 : WritingMode wm = aDesiredSize.GetWritingMode();
10439 66 :
10440 : bool needsReflow = NS_SUBTREE_DIRTY(this);
10441 132 :
10442 : // if we don't need a reflow then
10443 : // lets see if we are already that size. Yes? then don't even reflow. We are done.
10444 : if (!needsReflow) {
10445 66 :
10446 : if (aWidth != NS_INTRINSICSIZE && aHeight != NS_INTRINSICSIZE) {
10447 0 :
10448 : // if the new calculated size has a 0 width or a 0 height
10449 : if ((metrics->mLastSize.width == 0 || metrics->mLastSize.height == 0) && (aWidth == 0 || aHeight == 0)) {
10450 0 : needsReflow = false;
10451 0 : aDesiredSize.Width() = aWidth;
10452 0 : aDesiredSize.Height() = aHeight;
10453 0 : SetSize(aDesiredSize.Size(wm).ConvertTo(GetWritingMode(), wm));
10454 0 : } else {
10455 : aDesiredSize.Width() = metrics->mLastSize.width;
10456 0 : aDesiredSize.Height() = metrics->mLastSize.height;
10457 0 :
10458 : // remove the margin. The rect of our child does not include it but our calculated size does.
10459 : // don't reflow if we are already the right size
10460 : if (metrics->mLastSize.width == aWidth && metrics->mLastSize.height == aHeight)
10461 0 : needsReflow = false;
10462 : else
10463 : needsReflow = true;
10464 0 :
10465 : }
10466 : } else {
10467 : // if the width or height are intrinsic alway reflow because
10468 : // we don't know what it should be.
10469 : needsReflow = true;
10470 : }
10471 : }
10472 :
10473 : // ok now reflow the child into the spacers calculated space
10474 : if (needsReflow) {
10475 66 :
10476 : aDesiredSize.ClearSize();
10477 0 :
10478 : // create a reflow state to tell our child to flow at the given size.
10479 :
10480 : // Construct a bogus parent reflow state so that there's a usable
10481 : // containing block reflow state.
10482 : nsMargin margin(0,0,0,0);
10483 66 : GetXULMargin(margin);
10484 66 :
10485 : nsSize parentSize(aWidth, aHeight);
10486 66 : if (parentSize.height != NS_INTRINSICSIZE)
10487 0 : parentSize.height += margin.TopBottom();
10488 0 : if (parentSize.width != NS_INTRINSICSIZE)
10489 66 : parentSize.width += margin.LeftRight();
10490 132 :
10491 : nsIFrame *parentFrame = GetParent();
10492 66 : WritingMode parentWM = parentFrame->GetWritingMode();
10493 66 : ReflowInput
10494 : parentReflowInput(aPresContext, parentFrame, aRenderingContext,
10495 : LogicalSize(parentWM, parentSize),
10496 1 : ReflowInput::DUMMY_PARENT_REFLOW_STATE);
10497 66 :
10498 : // This may not do very much useful, but it's probably worth trying.
10499 : if (parentSize.width != NS_INTRINSICSIZE)
10500 0 : parentReflowInput.SetComputedWidth(std::max(parentSize.width, 0));
10501 0 : if (parentSize.height != NS_INTRINSICSIZE)
10502 66 : parentReflowInput.SetComputedHeight(std::max(parentSize.height, 0));
10503 0 : parentReflowInput.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
10504 132 : // XXX use box methods
10505 : parentFrame->GetXULPadding(parentReflowInput.ComputedPhysicalPadding());
10506 66 : parentFrame->GetXULBorder(parentReflowInput.ComputedPhysicalBorderPadding());
10507 0 : parentReflowInput.ComputedPhysicalBorderPadding() +=
10508 66 : parentReflowInput.ComputedPhysicalPadding();
10509 0 :
10510 : // Construct the parent chain manually since constructing it normally
10511 : // messes up dimensions.
10512 : const ReflowInput *outerReflowInput = aState.OuterReflowInput();
10513 1 : NS_ASSERTION(!outerReflowInput || outerReflowInput->mFrame != this,
10514 1 : "in and out of XUL on a single frame?");
10515 : const ReflowInput* parentRI;
10516 : if (outerReflowInput && outerReflowInput->mFrame == parentFrame) {
10517 66 : // We're a frame (such as a text control frame) that jumps into
10518 : // box reflow and then straight out of it on the child frame.
10519 : // This means we actually have a real parent reflow state.
10520 : // nsLayoutUtils::InflationMinFontSizeFor used to need this to be
10521 : // linked up correctly for text control frames, so do so here).
10522 : parentRI = outerReflowInput;
10523 : } else {
10524 : parentRI = &parentReflowInput;
10525 64 : }
10526 :
10527 : // XXX Is it OK that this reflow state has only one ancestor?
10528 : // (It used to have a bogus parent, skipping all the boxes).
10529 : WritingMode wm = GetWritingMode();
10530 66 : LogicalSize logicalSize(wm, nsSize(aWidth, aHeight));
10531 66 : logicalSize.BSize(wm) = NS_INTRINSICSIZE;
10532 66 : ReflowInput reflowInput(aPresContext, *parentRI, this,
10533 : logicalSize, nullptr,
10534 : ReflowInput::DUMMY_PARENT_REFLOW_STATE);
10535 66 :
10536 : // XXX_jwir3: This is somewhat fishy. If this is actually changing the value
10537 : // here (which it might be), then we should make sure that it's
10538 : // correct the first time around, rather than changing it later.
10539 : reflowInput.mCBReflowInput = parentRI;
10540 66 :
10541 : reflowInput.mReflowDepth = aState.GetReflowDepth();
10542 66 :
10543 : // mComputedWidth and mComputedHeight are content-box, not
10544 : // border-box
10545 : if (aWidth != NS_INTRINSICSIZE) {
10546 0 : nscoord computedWidth =
10547 : aWidth - reflowInput.ComputedPhysicalBorderPadding().LeftRight();
10548 0 : computedWidth = std::max(computedWidth, 0);
10549 0 : reflowInput.SetComputedWidth(computedWidth);
10550 0 : }
10551 :
10552 : // Most child frames of box frames (e.g. subdocument or scroll frames)
10553 : // need to be constrained to the provided size and overflow as necessary.
10554 : // The one exception are block frames, because we need to know their
10555 : // natural height excluding any overflow area which may be caused by
10556 : // various CSS effects such as shadow or outline.
10557 : if (!IsFrameOfType(eBlockFrame)) {
10558 0 : if (aHeight != NS_INTRINSICSIZE) {
10559 0 : nscoord computedHeight =
10560 : aHeight - reflowInput.ComputedPhysicalBorderPadding().TopBottom();
10561 62 : computedHeight = std::max(computedHeight, 0);
10562 0 : reflowInput.SetComputedHeight(computedHeight);
10563 0 : } else {
10564 : reflowInput.SetComputedHeight(
10565 0 : ComputeSize(aRenderingContext, wm,
10566 0 : logicalSize,
10567 : logicalSize.ISize(wm),
10568 0 : reflowInput.ComputedLogicalMargin().Size(wm),
10569 0 : reflowInput.ComputedLogicalBorderPadding().Size(wm) -
10570 0 : reflowInput.ComputedLogicalPadding().Size(wm),
10571 0 : reflowInput.ComputedLogicalPadding().Size(wm),
10572 52 : ComputeSizeFlags::eDefault).Height(wm));
10573 78 : }
10574 : }
10575 :
10576 : // Box layout calls SetRect before XULLayout, whereas non-box layout
10577 : // calls SetRect after Reflow.
10578 : // XXX Perhaps we should be doing this by twiddling the rect back to
10579 : // mLastSize before calling Reflow and then switching it back, but
10580 : // However, mLastSize can also be the size passed to BoxReflow by
10581 : // RefreshSizeCache, so that doesn't really make sense.
10582 : if (metrics->mLastSize.width != aWidth) {
10583 66 : reflowInput.SetHResize(true);
10584 11 :
10585 : // When font size inflation is enabled, a horizontal resize
10586 : // requires a full reflow. See ReflowInput::InitResizeFlags
10587 : // for more details.
10588 : if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
10589 11 : AddStateBits(NS_FRAME_IS_DIRTY);
10590 0 : }
10591 : }
10592 : if (metrics->mLastSize.height != aHeight) {
10593 0 : reflowInput.SetVResize(true);
10594 0 : }
10595 :
10596 : #ifdef DEBUG_REFLOW
10597 : nsAdaptorAddIndents();
10598 : printf("Size=(%d,%d)\n",reflowInput.ComputedWidth(),
10599 : reflowInput.ComputedHeight());
10600 : nsAdaptorAddIndents();
10601 : nsAdaptorPrintReason(reflowInput);
10602 : printf("\n");
10603 : #endif
10604 :
10605 : // place the child and reflow
10606 :
10607 : Reflow(aPresContext, aDesiredSize, reflowInput, status);
10608 0 :
10609 : NS_ASSERTION(status.IsComplete(), "bad status");
10610 0 :
10611 : uint32_t layoutFlags = aState.LayoutFlags();
10612 0 : nsContainerFrame::FinishReflowChild(this, aPresContext, aDesiredSize,
10613 66 : &reflowInput, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME);
10614 66 :
10615 : // Save the ascent. (bug 103925)
10616 : if (IsXULCollapsed()) {
10617 66 : metrics->mAscent = 0;
10618 0 : } else {
10619 : if (aDesiredSize.BlockStartAscent() ==
10620 0 : ReflowOutput::ASK_FOR_BASELINE) {
10621 : if (!nsLayoutUtils::GetFirstLineBaseline(wm, this, &metrics->mAscent))
10622 63 : metrics->mAscent = GetLogicalBaseline(wm);
10623 0 : } else
10624 : metrics->mAscent = aDesiredSize.BlockStartAscent();
10625 0 : }
10626 :
10627 : } else {
10628 : aDesiredSize.SetBlockStartAscent(metrics->mBlockAscent);
10629 0 : }
10630 :
10631 : #ifdef DEBUG_REFLOW
10632 : if (aHeight != NS_INTRINSICSIZE && aDesiredSize.Height() != aHeight)
10633 : {
10634 : nsAdaptorAddIndents();
10635 : printf("*****got taller!*****\n");
10636 :
10637 : }
10638 : if (aWidth != NS_INTRINSICSIZE && aDesiredSize.Width() != aWidth)
10639 : {
10640 : nsAdaptorAddIndents();
10641 : printf("*****got wider!******\n");
10642 :
10643 : }
10644 : #endif
10645 :
10646 : if (aWidth == NS_INTRINSICSIZE)
10647 : aWidth = aDesiredSize.Width();
10648 :
10649 : if (aHeight == NS_INTRINSICSIZE)
10650 : aHeight = aDesiredSize.Height();
10651 :
10652 : metrics->mLastSize.width = aDesiredSize.Width();
10653 66 : metrics->mLastSize.height = aDesiredSize.Height();
10654 66 :
10655 : #ifdef DEBUG_REFLOW
10656 : gIndent2--;
10657 : #endif
10658 : }
10659 66 :
10660 : nsBoxLayoutMetrics*
10661 : nsFrame::BoxMetrics() const
10662 446 : {
10663 : nsBoxLayoutMetrics* metrics = GetProperty(BoxMetricsProperty());
10664 892 : NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
10665 446 : return metrics;
10666 446 : }
10667 :
10668 : void
10669 : nsIFrame::UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
10670 0 : ServoRestyleState& aRestyleState)
10671 : {
10672 : #ifdef DEBUG
10673 : nsIFrame* parent = aChildFrame->GetInFlowParent();
10674 0 : if (aChildFrame->IsTableFrame()) {
10675 0 : parent = parent->GetParent();
10676 0 : }
10677 : if (parent->IsLineFrame()) {
10678 1 : parent = parent->GetParent();
10679 0 : }
10680 : MOZ_ASSERT(nsLayoutUtils::FirstContinuationOrIBSplitSibling(parent) == this,
10681 1 : "This should only be used for children!");
10682 : #endif // DEBUG
10683 : MOZ_ASSERT(!GetContent() || !aChildFrame->GetContent() ||
10684 0 : aChildFrame->GetContent() == GetContent(),
10685 : "What content node is it a frame for?");
10686 : MOZ_ASSERT(!aChildFrame->GetPrevContinuation(),
10687 0 : "Only first continuations should end up here");
10688 :
10689 : // We could force the caller to pass in the pseudo, since some callers know it
10690 : // statically... But this API is a bit nicer.
10691 : nsAtom* pseudo = aChildFrame->Style()->GetPseudo();
10692 2 : MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(pseudo), "Child is not an anon box?");
10693 1 : MOZ_ASSERT(!nsCSSAnonBoxes::IsNonInheritingAnonBox(pseudo),
10694 1 : "Why did the caller bother calling us?");
10695 :
10696 : // Anon boxes inherit from their parent; that's us.
10697 : RefPtr<ComputedStyle> newContext =
10698 : aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(pseudo, Style());
10699 3 :
10700 : nsChangeHint childHint =
10701 : UpdateStyleOfOwnedChildFrame(aChildFrame, newContext, aRestyleState);
10702 3 :
10703 : // Now that we've updated the style on aChildFrame, check whether it itself
10704 : // has anon boxes to deal with.
10705 : ServoRestyleState childrenState(
10706 : *aChildFrame, aRestyleState, childHint, ServoRestyleState::Type::InFlow);
10707 2 : aChildFrame->UpdateStyleOfOwnedAnonBoxes(childrenState);
10708 1 :
10709 : // Assuming anon boxes don't have ::backdrop associated with them... if that
10710 : // ever changes, we'd need to handle that here, like we do in
10711 : // RestyleManager::ProcessPostTraversal
10712 :
10713 : // We do need to handle block pseudo-elements here, though. Especially list
10714 : // bullets.
10715 : if (aChildFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
10716 0 : auto block = static_cast<nsBlockFrame*>(aChildFrame);
10717 1 : block->UpdatePseudoElementStyles(childrenState);
10718 1 : }
10719 : }
10720 1 :
10721 : /* static */ nsChangeHint
10722 : nsIFrame::UpdateStyleOfOwnedChildFrame(
10723 1 : nsIFrame* aChildFrame,
10724 : ComputedStyle* aNewComputedStyle,
10725 : ServoRestyleState& aRestyleState,
10726 : const Maybe<ComputedStyle*>& aContinuationComputedStyle)
10727 : {
10728 : MOZ_ASSERT(!aChildFrame->GetAdditionalComputedStyle(0),
10729 1 : "We don't handle additional styles here");
10730 :
10731 : // Figure out whether we have an actual change. It's important that we do
10732 : // this, for several reasons:
10733 : //
10734 : // 1) Even if all the child's changes are due to properties it inherits from
10735 : // us, it's possible that no one ever asked us for those style structs and
10736 : // hence changes to them aren't reflected in the changes handled at all.
10737 : //
10738 : // 2) Content can change stylesheets that change the styles of pseudos, and
10739 : // extensions can add/remove stylesheets that change the styles of
10740 : // anonymous boxes directly.
10741 : uint32_t equalStructs; // Not used, actually.
10742 : nsChangeHint childHint =
10743 : aChildFrame->Style()->CalcStyleDifference(aNewComputedStyle, &equalStructs);
10744 2 :
10745 : // CalcStyleDifference will handle caching structs on the new style, but only
10746 : // if we're not on a style worker thread.
10747 : MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal(),
10748 1 : "if we can get in here from style worker threads, then we need "
10749 : "a ResolveSameStructsAs call to ensure structs are cached on "
10750 : "aNewComputedStyle");
10751 :
10752 : // If aChildFrame is out of flow, then aRestyleState's "changes handled by the
10753 : // parent" doesn't apply to it, because it may have some other parent in the
10754 : // frame tree.
10755 : if (!aChildFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
10756 0 : childHint = NS_RemoveSubsumedHints(
10757 1 : childHint, aRestyleState.ChangesHandledFor(*aChildFrame));
10758 1 : }
10759 : if (childHint) {
10760 1 : if (childHint & nsChangeHint_ReconstructFrame) {
10761 0 : // If we generate a reconstruct here, remove any non-reconstruct hints we
10762 : // may have already generated for this content.
10763 : aRestyleState.ChangeList().PopChangesForContent(
10764 0 : aChildFrame->GetContent());
10765 0 : }
10766 : aRestyleState.ChangeList().AppendChange(
10767 0 : aChildFrame, aChildFrame->GetContent(), childHint);
10768 0 : }
10769 :
10770 : aChildFrame->SetComputedStyle(aNewComputedStyle);
10771 1 : ComputedStyle* continuationStyle =
10772 : aContinuationComputedStyle ? *aContinuationComputedStyle : aNewComputedStyle;
10773 1 : for (nsIFrame* kid = aChildFrame->GetNextContinuation();
10774 1 : kid;
10775 1 : kid = kid->GetNextContinuation()) {
10776 0 : MOZ_ASSERT(!kid->GetAdditionalComputedStyle(0));
10777 0 : kid->SetComputedStyle(continuationStyle);
10778 0 : }
10779 :
10780 : return childHint;
10781 1 : }
10782 :
10783 : /* static */ void
10784 : nsIFrame::AddInPopupStateBitToDescendants(nsIFrame* aFrame)
10785 0 : {
10786 : if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) &&
10787 0 : aFrame->TrackingVisibility()) {
10788 0 : // Assume all frames in popups are visible.
10789 : aFrame->IncApproximateVisibleCount();
10790 0 : }
10791 :
10792 : aFrame->AddStateBits(NS_FRAME_IN_POPUP);
10793 0 :
10794 : AutoTArray<nsIFrame::ChildList,4> childListArray;
10795 0 : aFrame->GetCrossDocChildLists(&childListArray);
10796 0 :
10797 : nsIFrame::ChildListArrayIterator lists(childListArray);
10798 : for (; !lists.IsDone(); lists.Next()) {
10799 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
10800 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
10801 0 : AddInPopupStateBitToDescendants(childFrames.get());
10802 0 : }
10803 : }
10804 : }
10805 0 :
10806 : /* static */ void
10807 : nsIFrame::RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame)
10808 25 : {
10809 : if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) ||
10810 0 : nsLayoutUtils::IsPopup(aFrame)) {
10811 0 : return;
10812 25 : }
10813 :
10814 : aFrame->RemoveStateBits(NS_FRAME_IN_POPUP);
10815 0 :
10816 : if (aFrame->TrackingVisibility()) {
10817 0 : // We assume all frames in popups are visible, so this decrement balances
10818 : // out the increment in AddInPopupStateBitToDescendants above.
10819 : aFrame->DecApproximateVisibleCount();
10820 0 : }
10821 :
10822 : AutoTArray<nsIFrame::ChildList,4> childListArray;
10823 0 : aFrame->GetCrossDocChildLists(&childListArray);
10824 0 :
10825 : nsIFrame::ChildListArrayIterator lists(childListArray);
10826 : for (; !lists.IsDone(); lists.Next()) {
10827 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
10828 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
10829 0 : RemoveInPopupStateBitFromDescendants(childFrames.get());
10830 0 : }
10831 : }
10832 : }
10833 :
10834 : void
10835 : nsIFrame::SetParent(nsContainerFrame* aParent)
10836 0 : {
10837 : // If our parent is a wrapper anon box, our new parent should be too. We
10838 : // _can_ change parent if our parent is a wrapper anon box, because some
10839 : // wrapper anon boxes can have continuations.
10840 : MOZ_ASSERT_IF(ParentIsWrapperAnonBox(),
10841 25 : aParent->Style()->IsInheritingAnonBox());
10842 :
10843 : // Note that the current mParent may already be destroyed at this point.
10844 : mParent = aParent;
10845 25 : MOZ_DIAGNOSTIC_ASSERT(!mParent || PresShell() == mParent->PresShell());
10846 25 : if (::IsXULBoxWrapped(this)) {
10847 0 : ::InitBoxMetrics(this, true);
10848 3 : } else {
10849 : // We could call Properties().Delete(BoxMetricsProperty()); here but
10850 : // that's kind of slow and re-parenting in such a way that we were
10851 : // IsXULBoxWrapped() before but not now should be very rare, so we'll just
10852 : // keep this unused frame property until this frame dies instead.
10853 : }
10854 :
10855 : if (GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
10856 50 : for (nsIFrame* f = aParent;
10857 0 : f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
10858 0 : f = f->GetParent()) {
10859 : f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
10860 0 : }
10861 : }
10862 :
10863 : if (HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)) {
10864 0 : for (nsIFrame* f = aParent; f; f = f->GetParent()) {
10865 0 : if (f->HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)) {
10866 0 : break;
10867 : }
10868 : f->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
10869 0 : }
10870 : }
10871 :
10872 : if (HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
10873 0 : for (nsIFrame* f = aParent; f; f = f->GetParent()) {
10874 0 : if (f->HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
10875 0 : break;
10876 : }
10877 : f->AddStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE);
10878 0 : }
10879 : }
10880 :
10881 : if (HasInvalidFrameInSubtree()) {
10882 1 : for (nsIFrame* f = aParent;
10883 2 : f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT | NS_FRAME_IS_NONDISPLAY);
10884 4 : f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
10885 : f->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
10886 0 : }
10887 : }
10888 :
10889 : if (aParent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
10890 1 : AddInPopupStateBitToDescendants(this);
10891 0 : } else {
10892 : RemoveInPopupStateBitFromDescendants(this);
10893 25 : }
10894 :
10895 : // If our new parent only has invalid children, then we just invalidate
10896 : // ourselves too. This is probably faster than clearing the flag all
10897 : // the way up the frame tree.
10898 : if (aParent->HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) {
10899 50 : InvalidateFrame();
10900 8 : } else {
10901 : SchedulePaint();
10902 17 : }
10903 : }
10904 25 :
10905 : void
10906 : nsIFrame::CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder,
10907 0 : nsDisplayList* aList,
10908 : bool* aCreatedContainerItem)
10909 : {
10910 : if (GetContent() &&
10911 575 : GetContent()->IsXULElement() &&
10912 537 : GetContent()->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
10913 320 : aList->AppendToTop(
10914 0 : MakeDisplayItem<nsDisplayOwnLayer>(aBuilder, this, aList, aBuilder->CurrentActiveScrolledRoot()));
10915 0 : if (aCreatedContainerItem) {
10916 0 : *aCreatedContainerItem = true;
10917 0 : }
10918 : }
10919 : }
10920 0 :
10921 : bool
10922 : nsIFrame::IsSelected() const
10923 410 : {
10924 : return (GetContent() && GetContent()->IsSelectionDescendant()) ?
10925 820 : IsFrameSelected() : false;
10926 0 : }
10927 :
10928 : bool
10929 : nsIFrame::IsVisuallyAtomic(EffectSet* aEffectSet,
10930 323 : const nsStyleDisplay* aStyleDisplay,
10931 : const nsStyleEffects* aStyleEffects) {
10932 : return HasOpacity(aEffectSet) ||
10933 598 : IsTransformed(aStyleDisplay) ||
10934 539 : aStyleDisplay->IsContainPaint() ||
10935 0 : // strictly speaking, 'perspective' doesn't require visual atomicity,
10936 : // but the spec says it acts like the rest of these
10937 : ChildrenHavePerspective(aStyleDisplay) ||
10938 528 : aStyleEffects->mMixBlendMode != NS_STYLE_BLEND_NORMAL ||
10939 851 : nsSVGIntegrationUtils::UsingEffectsForFrame(this);
10940 0 : }
10941 :
10942 : bool
10943 : nsIFrame::IsStackingContext(const nsStyleDisplay* aStyleDisplay,
10944 0 : const nsStylePosition* aStylePosition,
10945 : bool aIsPositioned,
10946 : bool aIsVisuallyAtomic)
10947 : {
10948 : return aIsVisuallyAtomic ||
10949 264 : (aIsPositioned && (aStyleDisplay->IsPositionForcingStackingContext() ||
10950 156 : aStylePosition->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
10951 300 : (aStyleDisplay->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
10952 0 : aStyleDisplay->mIsolation != NS_STYLE_ISOLATION_AUTO;
10953 0 : }
10954 :
10955 : bool
10956 : nsIFrame::IsStackingContext()
10957 0 : {
10958 : const nsStyleDisplay* disp = StyleDisplay();
10959 0 : const bool isVisuallyAtomic = IsVisuallyAtomic(EffectSet::GetEffectSet(this),
10960 0 : disp, StyleEffects());
10961 0 : if (isVisuallyAtomic) {
10962 0 : // If this is changed, the function above should be updated as well.
10963 : return true;
10964 : }
10965 :
10966 : const bool isPositioned = disp->IsAbsPosContainingBlock(this);
10967 0 : return IsStackingContext(disp, StylePosition(),
10968 0 : isPositioned, isVisuallyAtomic);
10969 0 : }
10970 :
10971 : static bool
10972 : IsFrameScrolledOutOfView(nsIFrame* aTarget,
10973 0 : const nsRect& aTargetRect,
10974 : nsIFrame* aParent)
10975 : {
10976 : nsIScrollableFrame* scrollableFrame =
10977 : nsLayoutUtils::GetNearestScrollableFrame(aParent,
10978 : nsLayoutUtils::SCROLLABLE_SAME_DOC |
10979 : nsLayoutUtils::SCROLLABLE_FIXEDPOS_FINDS_ROOT |
10980 : nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
10981 0 : if (!scrollableFrame) {
10982 0 : return false;
10983 : }
10984 :
10985 : nsIFrame *scrollableParent = do_QueryFrame(scrollableFrame);
10986 0 : nsRect scrollableRect =
10987 : scrollableParent->GetVisualOverflowRectRelativeToSelf();
10988 0 : // We consider that the target is scrolled out if the scrollable frame is
10989 : // empty.
10990 : if (scrollableRect.IsEmpty()) {
10991 0 : return true;
10992 : }
10993 :
10994 : nsRect transformedRect =
10995 : nsLayoutUtils::TransformFrameRectToAncestor(aTarget,
10996 : aTargetRect,
10997 : scrollableParent);
10998 0 :
10999 : if (transformedRect.IsEmpty()) {
11000 0 : // If the transformed rect is empty it represents a line or a point that we
11001 : // should check is outside the the scrollable rect.
11002 : if (transformedRect.x > scrollableRect.XMost() ||
11003 0 : transformedRect.y > scrollableRect.YMost() ||
11004 0 : scrollableRect.x > transformedRect.XMost() ||
11005 0 : scrollableRect.y > transformedRect.YMost()) {
11006 0 : return true;
11007 : }
11008 : } else if (!transformedRect.Intersects(scrollableRect)) {
11009 0 : return true;
11010 : }
11011 :
11012 : nsIFrame* parent = scrollableParent->GetParent();
11013 0 : if (!parent) {
11014 0 : return false;
11015 : }
11016 :
11017 : return IsFrameScrolledOutOfView(aTarget, aTargetRect, parent);
11018 0 : }
11019 :
11020 : bool
11021 : nsIFrame::IsScrolledOutOfView()
11022 0 : {
11023 : nsRect rect = GetVisualOverflowRectRelativeToSelf();
11024 0 : return IsFrameScrolledOutOfView(this, rect, this);
11025 0 : }
11026 :
11027 : gfx::Matrix
11028 : nsIFrame::ComputeWidgetTransform()
11029 0 : {
11030 : const nsStyleUIReset* uiReset = StyleUIReset();
11031 0 : if (!uiReset->mSpecifiedWindowTransform) {
11032 0 : return gfx::Matrix();
11033 0 : }
11034 :
11035 : nsStyleTransformMatrix::TransformReferenceBox refBox;
11036 0 : refBox.Init(GetSize());
11037 0 :
11038 : nsPresContext* presContext = PresContext();
11039 0 : int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
11040 0 : bool dummyBool;
11041 : gfx::Matrix4x4 matrix =
11042 : nsStyleTransformMatrix::ReadTransforms(uiReset->mSpecifiedWindowTransform->mHead,
11043 0 : refBox,
11044 : float(appUnitsPerDevPixel),
11045 : &dummyBool);
11046 0 :
11047 : // Apply the -moz-window-transform-origin translation to the matrix.
11048 : Point transformOrigin =
11049 : nsStyleTransformMatrix::Convert2DPosition(uiReset->mWindowTransformOrigin,
11050 : refBox, appUnitsPerDevPixel);
11051 0 : matrix.ChangeBasis(Point3D(transformOrigin.x, transformOrigin.y, 0));
11052 0 :
11053 : gfx::Matrix result2d;
11054 0 : if (!matrix.CanDraw2D(&result2d)) {
11055 0 : // FIXME: It would be preferable to reject non-2D transforms at parse time.
11056 : NS_WARNING("-moz-window-transform does not describe a 2D transform, "
11057 : "but only 2d transforms are supported");
11058 0 : return gfx::Matrix();
11059 0 : }
11060 :
11061 : return result2d;
11062 0 : }
11063 :
11064 : static already_AddRefed<nsIWidget>
11065 : GetWindowWidget(nsPresContext* aPresContext)
11066 0 : {
11067 : // We want to obtain the widget for the window. We can't use any of these
11068 : // methods: nsPresContext::GetRootWidget, nsPresContext::GetNearestWidget,
11069 : // nsIFrame::GetNearestWidget because those deal with child widgets and
11070 : // there is no parent widget connection between child widgets and the
11071 : // window widget that contains them.
11072 : nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
11073 0 : nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
11074 0 : if (!baseWindow) {
11075 0 : return nullptr;
11076 : }
11077 :
11078 : nsCOMPtr<nsIWidget> mainWidget;
11079 0 : baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
11080 0 : return mainWidget.forget();
11081 0 : }
11082 :
11083 : void
11084 : nsIFrame::UpdateWidgetProperties()
11085 0 : {
11086 : nsPresContext* presContext = PresContext();
11087 0 : if (presContext->IsRoot() || !presContext->IsChrome()) {
11088 0 : // Don't do anything for documents that aren't the root chrome document.
11089 : return;
11090 : }
11091 : nsIFrame* rootFrame =
11092 : presContext->FrameConstructor()->GetRootElementStyleFrame();
11093 0 : if (this != rootFrame) {
11094 0 : // Only the window's root style frame is relevant for widget properties.
11095 : return;
11096 : }
11097 : if (nsCOMPtr<nsIWidget> widget = GetWindowWidget(presContext)) {
11098 0 : widget->SetWindowOpacity(StyleUIReset()->mWindowOpacity);
11099 0 : widget->SetWindowTransform(ComputeWidgetTransform());
11100 0 : }
11101 : }
11102 :
11103 : void
11104 : nsIFrame::DoUpdateStyleOfOwnedAnonBoxes(ServoRestyleState& aRestyleState)
11105 1 : {
11106 : // As a special case, we check for {ib}-split block frames here, rather
11107 : // than have an nsInlineFrame::AppendDirectlyOwnedAnonBoxes implementation
11108 : // that returns them.
11109 : //
11110 : // (If we did handle them in AppendDirectlyOwnedAnonBoxes, we would have to
11111 : // return *all* of the in-flow {ib}-split block frames, not just the first
11112 : // one. For restyling, we really just need the first in flow, and the other
11113 : // user of the AppendOwnedAnonBoxes API, AllChildIterator, doesn't need to
11114 : // know about them at all, since these block frames never create NAC. So we
11115 : // avoid any unncessary hashtable lookups for the {ib}-split frames by calling
11116 : // UpdateStyleOfOwnedAnonBoxesForIBSplit directly here.)
11117 : if (IsInlineFrame()) {
11118 1 : if ((GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
11119 0 : static_cast<nsInlineFrame*>(this)->UpdateStyleOfOwnedAnonBoxesForIBSplit(
11120 : aRestyleState);
11121 0 : }
11122 : return;
11123 0 : }
11124 :
11125 : AutoTArray<OwnedAnonBox,4> frames;
11126 2 : AppendDirectlyOwnedAnonBoxes(frames);
11127 1 : for (OwnedAnonBox& box : frames) {
11128 1 : if (box.mUpdateStyleFn) {
11129 1 : box.mUpdateStyleFn(this, box.mAnonBoxFrame, aRestyleState);
11130 0 : } else {
11131 : UpdateStyleOfChildAnonBox(box.mAnonBoxFrame, aRestyleState);
11132 1 : }
11133 : }
11134 : }
11135 :
11136 : /* virtual */ void
11137 : nsIFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
11138 0 : {
11139 : MOZ_ASSERT(!(GetStateBits() & NS_FRAME_OWNS_ANON_BOXES));
11140 0 : MOZ_ASSERT(false, "Why did this get called?");
11141 0 : }
11142 :
11143 : void
11144 : nsIFrame::DoAppendOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
11145 374 : {
11146 : size_t i = aResult.Length();
11147 1 : AppendDirectlyOwnedAnonBoxes(aResult);
11148 374 :
11149 : // After appending the directly owned anonymous boxes of this frame to
11150 : // aResult above, we need to check each of them to see if they own
11151 : // any anonymous boxes themselves. Note that we keep progressing
11152 : // through aResult, looking for additional entries in aResult from these
11153 : // subsequent AppendDirectlyOwnedAnonBoxes calls. (Thus we can't
11154 : // use a ranged for loop here.)
11155 :
11156 : while (i < aResult.Length()) {
11157 1870 : nsIFrame* f = aResult[i].mAnonBoxFrame;
11158 748 : if (f->GetStateBits() & NS_FRAME_OWNS_ANON_BOXES) {
11159 748 : f->AppendDirectlyOwnedAnonBoxes(aResult);
11160 0 : }
11161 : ++i;
11162 1 : }
11163 : }
11164 374 :
11165 : nsIFrame::CaretPosition::CaretPosition()
11166 0 : : mContentOffset(0)
11167 0 : {
11168 : }
11169 0 :
11170 : nsIFrame::CaretPosition::~CaretPosition()
11171 0 : {
11172 : }
11173 0 :
11174 : bool
11175 : nsFrame::HasCSSAnimations()
11176 48 : {
11177 : auto collection =
11178 : AnimationCollection<CSSAnimation>::GetAnimationCollection(this);
11179 48 : return collection && collection->mAnimations.Length() > 0;
11180 0 : }
11181 :
11182 : bool
11183 : nsFrame::HasCSSTransitions()
11184 48 : {
11185 : auto collection =
11186 : AnimationCollection<CSSTransition>::GetAnimationCollection(this);
11187 48 : return collection && collection->mAnimations.Length() > 0;
11188 0 : }
11189 :
11190 : void
11191 : nsIFrame::AddSizeOfExcludingThisForTree(nsWindowSizes& aSizes) const
11192 0 : {
11193 : aSizes.mLayoutFramePropertiesSize +=
11194 0 : mProperties.SizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
11195 156 :
11196 : // We don't do this for Gecko because this stuff is stored in the nsPresArena
11197 : // and so measured elsewhere.
11198 : if (!aSizes.mState.HaveSeenPtr(mComputedStyle)) {
11199 234 : mComputedStyle->AddSizeOfIncludingThis(
11200 1 : aSizes, &aSizes.mLayoutComputedValuesNonDom);
11201 13 : }
11202 :
11203 : // And our additional styles.
11204 : int32_t index = 0;
11205 : while (auto* extra = GetAdditionalComputedStyle(index++)) {
11206 78 : if (!aSizes.mState.HaveSeenPtr(extra)) {
11207 0 : extra->AddSizeOfIncludingThis(
11208 0 : aSizes, &aSizes.mLayoutComputedValuesNonDom);
11209 0 : }
11210 : }
11211 :
11212 : FrameChildListIterator iter(this);
11213 156 : while (!iter.IsDone()) {
11214 208 : for (const nsIFrame* f : iter.CurrentList()) {
11215 260 : f->AddSizeOfExcludingThisForTree(aSizes);
11216 65 : }
11217 : iter.Next();
11218 65 : }
11219 : }
11220 0 :
11221 : CompositorHitTestInfo
11222 : nsIFrame::GetCompositorHitTestInfo(nsDisplayListBuilder* aBuilder)
11223 620 : {
11224 : CompositorHitTestInfo result = CompositorHitTestInfo::eInvisibleToHitTest;
11225 620 :
11226 : if (aBuilder->IsInsidePointerEventsNoneDoc()) {
11227 620 : // Somewhere up the parent document chain is a subdocument with pointer-
11228 : // events:none set on it.
11229 : return result;
11230 : }
11231 : if (!GetParent()) {
11232 620 : MOZ_ASSERT(IsViewportFrame());
11233 0 : // Viewport frames are never event targets, other frames, like canvas frames,
11234 : // are the event targets for any regions viewport frames may cover.
11235 : return result;
11236 : }
11237 : const uint8_t pointerEvents = StyleUserInterface()->GetEffectivePointerEvents(this);
11238 0 : if (pointerEvents == NS_STYLE_POINTER_EVENTS_NONE) {
11239 612 : return result;
11240 : }
11241 : if (!StyleVisibility()->IsVisible()) {
11242 0 : return result;
11243 : }
11244 :
11245 : // Anything that didn't match the above conditions is visible to hit-testing.
11246 : result |= CompositorHitTestInfo::eVisibleToHitTest;
11247 556 :
11248 : if (aBuilder->IsBuildingNonLayerizedScrollbar() ||
11249 0 : aBuilder->GetAncestorHasApzAwareEventHandler()) {
11250 0 : // Scrollbars may be painted into a layer below the actual layer they will
11251 : // scroll, and therefore wheel events may be dispatched to the outer frame
11252 : // instead of the intended scrollframe. To address this, we force a d-t-c
11253 : // region on scrollbar frames that won't be placed in their own layer. See
11254 : // bug 1213324 for details.
11255 : result |= CompositorHitTestInfo::eDispatchToContent;
11256 : } else if (IsObjectFrame()) {
11257 0 : // If the frame is a plugin frame and wants to handle wheel events as
11258 : // default action, we should add the frame to dispatch-to-content region.
11259 : nsPluginFrame* pluginFrame = do_QueryFrame(this);
11260 0 : if (pluginFrame && pluginFrame->WantsToHandleWheelEventAsDefaultAction()) {
11261 0 : result |= CompositorHitTestInfo::eDispatchToContent;
11262 : }
11263 : }
11264 :
11265 : // Inherit the touch-action flags from the parent, if there is one. We do this
11266 556 : // because of how the touch-action on a frame combines the touch-action from
11267 556 : // ancestor DOM elements. Refer to the documentation in TouchActionHelper.cpp
11268 0 : // for details; this code is meant to be equivalent to that code, but woven
11269 : // into the top-down recursive display list building process.
11270 0 : CompositorHitTestInfo inheritedTouchAction = CompositorHitTestInfo::eInvisibleToHitTest;
11271 : if (nsDisplayCompositorHitTestInfo* parentInfo = aBuilder->GetCompositorHitTestInfo()) {
11272 : inheritedTouchAction = (parentInfo->HitTestInfo() & CompositorHitTestInfo::eTouchActionMask);
11273 556 : }
11274 :
11275 0 : nsIFrame* touchActionFrame = this;
11276 : if (nsIScrollableFrame* scrollFrame = nsLayoutUtils::GetScrollableFrameFor(this)) {
11277 : touchActionFrame = do_QueryFrame(scrollFrame);
11278 : // On scrollframes, stop inheriting the pan-x and pan-y flags; instead,
11279 : // reset them back to zero to allow panning on the scrollframe unless we
11280 : // encounter an element that disables it that's inside the scrollframe.
11281 556 : // This is equivalent to the |considerPanning| variable in
11282 : // TouchActionHelper.cpp, but for a top-down traversal.
11283 0 : CompositorHitTestInfo panMask = CompositorHitTestInfo::eTouchActionPanXDisabled
11284 : | CompositorHitTestInfo::eTouchActionPanYDisabled;
11285 : inheritedTouchAction &= ~panMask;
11286 0 : }
11287 :
11288 : result |= inheritedTouchAction;
11289 0 :
11290 : const uint32_t touchAction = nsLayoutUtils::GetTouchActionFromFrame(touchActionFrame);
11291 0 : // The CSS allows the syntax auto | none | [pan-x || pan-y] | manipulation
11292 : // so we can eliminate some combinations of things.
11293 : if (touchAction == NS_STYLE_TOUCH_ACTION_AUTO) {
11294 : // nothing to do
11295 : } else if (touchAction & NS_STYLE_TOUCH_ACTION_MANIPULATION) {
11296 556 : result |= CompositorHitTestInfo::eTouchActionDoubleTapZoomDisabled;
11297 556 : } else {
11298 0 : // This path handles the cases none | [pan-x || pan-y] and so both
11299 0 : // double-tap and pinch zoom are disabled in here.
11300 0 : result |= CompositorHitTestInfo::eTouchActionPinchZoomDisabled
11301 0 : | CompositorHitTestInfo::eTouchActionDoubleTapZoomDisabled;
11302 :
11303 : if (!(touchAction & NS_STYLE_TOUCH_ACTION_PAN_X)) {
11304 : result |= CompositorHitTestInfo::eTouchActionPanXDisabled;
11305 : }
11306 : if (!(touchAction & NS_STYLE_TOUCH_ACTION_PAN_Y)) {
11307 : result |= CompositorHitTestInfo::eTouchActionPanYDisabled;
11308 0 : }
11309 : if (touchAction & NS_STYLE_TOUCH_ACTION_NONE) {
11310 : // all the touch-action disabling flags will already have been set above
11311 : MOZ_ASSERT((result & CompositorHitTestInfo::eTouchActionMask)
11312 : == CompositorHitTestInfo::eTouchActionMask);
11313 : }
11314 : }
11315 :
11316 : const Maybe<ScrollDirection> scrollDirection = aBuilder->GetCurrentScrollbarDirection();
11317 556 : if (scrollDirection.isSome()) {
11318 : if (GetContent()->IsXULElement(nsGkAtoms::thumb)) {
11319 : const bool thumbGetsLayer = aBuilder->GetCurrentScrollbarTarget() !=
11320 : layers::FrameMetrics::NULL_SCROLL_ID;
11321 : if (thumbGetsLayer) {
11322 0 : result |= CompositorHitTestInfo::eScrollbarThumb;
11323 : } else {
11324 109 : result |= CompositorHitTestInfo::eDispatchToContent;
11325 37 : }
11326 0 : }
11327 6 :
11328 0 : if (*scrollDirection == ScrollDirection::eVertical) {
11329 0 : result |= CompositorHitTestInfo::eScrollbarVertical;
11330 0 : }
11331 :
11332 : // includes the ScrollbarFrame, SliderFrame, anything else that
11333 : // might be inside the xul:scrollbar
11334 35 : result |= CompositorHitTestInfo::eScrollbar;
11335 : }
11336 :
11337 : return result;
11338 409 : }
11339 :
11340 409 : // Returns true if we can guarantee there is no visible descendants.
11341 : static bool
11342 : HasNoVisibleDescendants(const nsIFrame* aFrame)
11343 0 : {
11344 376 : for (nsIFrame::ChildListIterator lists(aFrame);
11345 : !lists.IsDone();
11346 4 : lists.Next()) {
11347 : for (nsIFrame* f : lists.CurrentList()) {
11348 : if (nsPlaceholderFrame::GetRealFrameFor(f)->
11349 37 : IsVisibleOrMayHaveVisibleDescendants()) {
11350 : return false;
11351 0 : }
11352 : }
11353 : }
11354 : return true;
11355 : }
11356 :
11357 : void
11358 : nsIFrame::UpdateVisibleDescendantsState()
11359 : {
11360 : if (StyleVisibility()->IsVisible()) {
11361 : // Notify invisible ancestors that a visible descendant exists now.
11362 : nsIFrame* ancestor;
11363 : for (ancestor = GetInFlowParent();
11364 : ancestor && !ancestor->StyleVisibility()->IsVisible();
11365 : ancestor = ancestor->GetInFlowParent()) {
11366 : ancestor->mAllDescendantsAreInvisible = false;
11367 : }
11368 : } else {
11369 : mAllDescendantsAreInvisible = HasNoVisibleDescendants(this);
11370 : }
11371 : }
11372 :
11373 : // Box layout debugging
11374 : #ifdef DEBUG_REFLOW
11375 : int32_t gIndent2 = 0;
11376 :
11377 : void
11378 : nsAdaptorAddIndents()
11379 : {
11380 : for(int32_t i=0; i < gIndent2; i++)
11381 : {
11382 : printf(" ");
11383 : }
11384 : }
11385 :
11386 : void
11387 : nsAdaptorPrintReason(ReflowInput& aReflowInput)
11388 : {
11389 : char* reflowReasonString;
11390 :
11391 : switch(aReflowInput.reason)
11392 : {
11393 : case eReflowReason_Initial:
11394 : reflowReasonString = "initial";
11395 : break;
11396 :
11397 : case eReflowReason_Resize:
11398 : reflowReasonString = "resize";
11399 : break;
11400 : case eReflowReason_Dirty:
11401 : reflowReasonString = "dirty";
11402 : break;
11403 : case eReflowReason_StyleChange:
11404 : reflowReasonString = "stylechange";
11405 : break;
11406 : case eReflowReason_Incremental:
11407 : {
11408 : switch (aReflowInput.reflowCommand->Type()) {
11409 : case eReflowType_StyleChanged:
11410 : reflowReasonString = "incremental (StyleChanged)";
11411 : break;
11412 0 : case eReflowType_ReflowDirty:
11413 : reflowReasonString = "incremental (ReflowDirty)";
11414 : break;
11415 0 : default:
11416 0 : reflowReasonString = "incremental (Unknown)";
11417 0 : }
11418 : }
11419 : break;
11420 0 : default:
11421 : reflowReasonString = "unknown";
11422 0 : break;
11423 : }
11424 :
11425 77 : printf("%s",reflowReasonString);
11426 : }
11427 154 :
11428 : #endif
11429 0 :
11430 0 : #ifdef DEBUG
11431 : static void
11432 77 : GetTagName(nsFrame* aFrame, nsIContent* aContent, int aResultSize,
11433 : char* aResult)
11434 : {
11435 77 : if (aContent) {
11436 : snprintf(aResult, aResultSize, "%s@%p",
11437 154 : nsAtomCString(aContent->NodeInfo()->NameAtom()).get(), aFrame);
11438 : }
11439 0 : else {
11440 0 : snprintf(aResult, aResultSize, "@%p", aFrame);
11441 : }
11442 0 : }
11443 0 :
11444 : void
11445 77 : nsFrame::Trace(const char* aMethod, bool aEnter)
11446 : {
11447 : if (NS_FRAME_LOG_TEST(sFrameLogModule, NS_FRAME_TRACE_CALLS)) {
11448 0 : char tagbuf[40];
11449 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
11450 0 : printf_stderr("%s: %s %s", tagbuf, aEnter ? "enter" : "exit", aMethod);
11451 : }
11452 : }
11453 :
11454 0 : void
11455 0 : nsFrame::Trace(const char* aMethod, bool aEnter, const nsReflowStatus& aStatus)
11456 0 : {
11457 : if (NS_FRAME_LOG_TEST(sFrameLogModule, NS_FRAME_TRACE_CALLS)) {
11458 : char tagbuf[40];
11459 0 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
11460 0 : printf_stderr("%s: %s %s, status=%scomplete%s",
11461 : tagbuf, aEnter ? "enter" : "exit", aMethod,
11462 0 : aStatus.IsIncomplete() ? "not" : "",
11463 : (aStatus.NextInFlowNeedsReflow()) ? "+reflow" : "");
11464 : }
11465 299 : }
11466 :
11467 578 : void
11468 558 : nsFrame::TraceMsg(const char* aFormatString, ...)
11469 : {
11470 : if (NS_FRAME_LOG_TEST(sFrameLogModule, NS_FRAME_TRACE_CALLS)) {
11471 299 : // Format arguments into a buffer
11472 : char argbuf[200];
11473 : va_list ap;
11474 : va_start(ap, aFormatString);
11475 : VsprintfLiteral(argbuf, aFormatString, ap);
11476 279 : va_end(ap);
11477 :
11478 : char tagbuf[40];
11479 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
11480 279 : printf_stderr("%s: %s", tagbuf, argbuf);
11481 279 : }
11482 : }
11483 279 :
11484 1 : void
11485 279 : nsFrame::VerifyDirtyBitSet(const nsFrameList& aFrameList)
11486 : {
11487 0 : for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
11488 : NS_ASSERTION(e.get()->GetStateBits() & NS_FRAME_IS_DIRTY,
11489 0 : "dirty bit not set");
11490 279 : }
11491 1 : }
11492 :
11493 395 : // Start Display Reflow
11494 0 : #ifdef DEBUG
11495 :
11496 395 : DR_cookie::DR_cookie(nsPresContext* aPresContext,
11497 0 : nsIFrame* aFrame,
11498 395 : const ReflowInput& aReflowInput,
11499 : ReflowOutput& aMetrics,
11500 790 : nsReflowStatus& aStatus)
11501 : :mPresContext(aPresContext), mFrame(aFrame), mReflowInput(aReflowInput), mMetrics(aMetrics), mStatus(aStatus)
11502 1 : {
11503 395 : MOZ_COUNT_CTOR(DR_cookie);
11504 1 : mValue = nsFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowInput);
11505 : }
11506 182 :
11507 : DR_cookie::~DR_cookie()
11508 : {
11509 182 : MOZ_COUNT_DTOR(DR_cookie);
11510 : nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue);
11511 : }
11512 1 :
11513 : DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame)
11514 182 : : mFrame(aFrame)
11515 182 : {
11516 1 : MOZ_COUNT_CTOR(DR_layout_cookie);
11517 : mValue = nsFrame::DisplayLayoutEnter(mFrame);
11518 1 : }
11519 :
11520 182 : DR_layout_cookie::~DR_layout_cookie()
11521 1 : {
11522 1 : MOZ_COUNT_DTOR(DR_layout_cookie);
11523 : nsFrame::DisplayLayoutExit(mFrame, mValue);
11524 1 : }
11525 :
11526 : DR_intrinsic_width_cookie::DR_intrinsic_width_cookie(
11527 0 : nsIFrame* aFrame,
11528 : const char* aType,
11529 : nscoord& aResult)
11530 0 : : mFrame(aFrame)
11531 : , mType(aType)
11532 3888 : , mResult(aResult)
11533 0 : {
11534 3888 : MOZ_COUNT_CTOR(DR_intrinsic_width_cookie);
11535 : mValue = nsFrame::DisplayIntrinsicISizeEnter(mFrame, mType);
11536 7776 : }
11537 :
11538 0 : DR_intrinsic_width_cookie::~DR_intrinsic_width_cookie()
11539 3888 : {
11540 3888 : MOZ_COUNT_DTOR(DR_intrinsic_width_cookie);
11541 : nsFrame::DisplayIntrinsicISizeExit(mFrame, mType, mResult, mValue);
11542 0 : }
11543 :
11544 : DR_intrinsic_size_cookie::DR_intrinsic_size_cookie(
11545 : nsIFrame* aFrame,
11546 : const char* aType,
11547 : nsSize& aResult)
11548 307 : : mFrame(aFrame)
11549 : , mType(aType)
11550 307 : , mResult(aResult)
11551 : {
11552 0 : MOZ_COUNT_CTOR(DR_intrinsic_size_cookie);
11553 0 : mValue = nsFrame::DisplayIntrinsicSizeEnter(mFrame, mType);
11554 : }
11555 :
11556 0 : DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie()
11557 : {
11558 0 : MOZ_COUNT_DTOR(DR_intrinsic_size_cookie);
11559 : nsFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue);
11560 0 : }
11561 307 :
11562 0 : DR_init_constraints_cookie::DR_init_constraints_cookie(
11563 : nsIFrame* aFrame,
11564 0 : ReflowInput* aState,
11565 : nscoord aCBWidth,
11566 : nscoord aCBHeight,
11567 : const nsMargin* aMargin,
11568 : const nsMargin* aPadding)
11569 : : mFrame(aFrame)
11570 307 : , mState(aState)
11571 : {
11572 307 : MOZ_COUNT_CTOR(DR_init_constraints_cookie);
11573 : mValue = ReflowInput::DisplayInitConstraintsEnter(mFrame, mState,
11574 0 : aCBWidth, aCBHeight,
11575 307 : aMargin, aPadding);
11576 : }
11577 :
11578 : DR_init_constraints_cookie::~DR_init_constraints_cookie()
11579 307 : {
11580 : MOZ_COUNT_DTOR(DR_init_constraints_cookie);
11581 614 : ReflowInput::DisplayInitConstraintsExit(mFrame, mState, mValue);
11582 : }
11583 0 :
11584 0 : DR_init_offsets_cookie::DR_init_offsets_cookie(
11585 307 : nsIFrame* aFrame,
11586 : SizeComputationInput* aState,
11587 307 : nscoord aPercentBasis,
11588 : WritingMode aCBWritingMode,
11589 0 : const nsMargin* aMargin,
11590 : const nsMargin* aPadding)
11591 307 : : mFrame(aFrame)
11592 : , mState(aState)
11593 307 : {
11594 0 : MOZ_COUNT_CTOR(DR_init_offsets_cookie);
11595 0 : mValue = SizeComputationInput::DisplayInitOffsetsEnter(mFrame, mState,
11596 : aPercentBasis,
11597 614 : aCBWritingMode,
11598 : aMargin, aPadding);
11599 307 : }
11600 0 :
11601 0 : DR_init_offsets_cookie::~DR_init_offsets_cookie()
11602 : {
11603 : MOZ_COUNT_DTOR(DR_init_offsets_cookie);
11604 : SizeComputationInput::DisplayInitOffsetsExit(mFrame, mState, mValue);
11605 : }
11606 :
11607 : DR_init_type_cookie::DR_init_type_cookie(
11608 : nsIFrame* aFrame,
11609 : ReflowInput* aState)
11610 : : mFrame(aFrame)
11611 : , mState(aState)
11612 : {
11613 : MOZ_COUNT_CTOR(DR_init_type_cookie);
11614 : mValue = ReflowInput::DisplayInitFrameTypeEnter(mFrame, mState);
11615 : }
11616 :
11617 : DR_init_type_cookie::~DR_init_type_cookie()
11618 : {
11619 : MOZ_COUNT_DTOR(DR_init_type_cookie);
11620 : ReflowInput::DisplayInitFrameTypeExit(mFrame, mState, mValue);
11621 : }
11622 :
11623 : struct DR_FrameTypeInfo;
11624 : struct DR_FrameTreeNode;
11625 : struct DR_Rule;
11626 :
11627 : struct DR_State
11628 : {
11629 : DR_State();
11630 : ~DR_State();
11631 : void Init();
11632 : void AddFrameTypeInfo(LayoutFrameType aFrameType,
11633 : const char* aFrameNameAbbrev,
11634 : const char* aFrameName);
11635 : DR_FrameTypeInfo* GetFrameTypeInfo(LayoutFrameType aFrameType);
11636 : DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName);
11637 : void InitFrameTypeTable();
11638 : DR_FrameTreeNode* CreateTreeNode(nsIFrame* aFrame,
11639 : const ReflowInput* aReflowInput);
11640 : void FindMatchingRule(DR_FrameTreeNode& aNode);
11641 : bool RuleMatches(DR_Rule& aRule,
11642 : DR_FrameTreeNode& aNode);
11643 : bool GetToken(FILE* aFile,
11644 : char* aBuf,
11645 : size_t aBufSize);
11646 : DR_Rule* ParseRule(FILE* aFile);
11647 : void ParseRulesFile();
11648 : void AddRule(nsTArray<DR_Rule*>& aRules,
11649 : DR_Rule& aRule);
11650 : bool IsWhiteSpace(int c);
11651 : bool GetNumber(char* aBuf,
11652 : int32_t& aNumber);
11653 : void PrettyUC(nscoord aSize,
11654 : char* aBuf,
11655 : int aBufSize);
11656 : void PrintMargin(const char* tag, const nsMargin* aMargin);
11657 : void DisplayFrameTypeInfo(nsIFrame* aFrame,
11658 : int32_t aIndent);
11659 0 : void DeleteTreeNode(DR_FrameTreeNode& aNode);
11660 0 :
11661 : bool mInited;
11662 : bool mActive;
11663 : int32_t mCount;
11664 : int32_t mAssert;
11665 : int32_t mIndent;
11666 : bool mIndentUndisplayedFrames;
11667 : bool mDisplayPixelErrors;
11668 : nsTArray<DR_Rule*> mWildRules;
11669 0 : nsTArray<DR_FrameTypeInfo> mFrameTypeTable;
11670 : // reflow specific state
11671 0 : nsTArray<DR_FrameTreeNode*> mFrameTreeLeaves;
11672 0 : };
11673 :
11674 0 : static DR_State *DR_state; // the one and only DR_State
11675 0 :
11676 : struct DR_RulePart
11677 : {
11678 : explicit DR_RulePart(LayoutFrameType aFrameType)
11679 0 : : mFrameType(aFrameType)
11680 0 : , mNext(0)
11681 0 : {}
11682 0 :
11683 0 : void Destroy();
11684 0 :
11685 0 : LayoutFrameType mFrameType;
11686 : DR_RulePart* mNext;
11687 : };
11688 :
11689 : void DR_RulePart::Destroy()
11690 : {
11691 : if (mNext) {
11692 : mNext->Destroy();
11693 : }
11694 0 : delete this;
11695 : }
11696 0 :
11697 0 : struct DR_Rule
11698 0 : {
11699 0 : DR_Rule() : mLength(0), mTarget(nullptr), mDisplay(false) {
11700 0 : MOZ_COUNT_CTOR(DR_Rule);
11701 : }
11702 70 : ~DR_Rule() {
11703 : if (mTarget) mTarget->Destroy();
11704 : MOZ_COUNT_DTOR(DR_Rule);
11705 : }
11706 : void AddPart(LayoutFrameType aFrameType);
11707 105 :
11708 : uint32_t mLength;
11709 70 : DR_RulePart* mTarget;
11710 35 : bool mDisplay;
11711 0 : };
11712 :
11713 35 : void
11714 : DR_Rule::AddPart(LayoutFrameType aFrameType)
11715 : {
11716 : DR_RulePart* newPart = new DR_RulePart(aFrameType);
11717 : newPart->mNext = mTarget;
11718 : mTarget = newPart;
11719 : mLength++;
11720 : }
11721 :
11722 : struct DR_FrameTypeInfo
11723 35 : {
11724 : DR_FrameTypeInfo(LayoutFrameType aFrameType,
11725 70 : const char* aFrameNameAbbrev,
11726 : const char* aFrameName);
11727 35 : ~DR_FrameTypeInfo() {
11728 35 : int32_t numElements;
11729 35 : numElements = mRules.Length();
11730 35 : for (int32_t i = numElements - 1; i >= 0; i--) {
11731 : delete mRules.ElementAt(i);
11732 : }
11733 : }
11734 0 :
11735 : LayoutFrameType mType;
11736 0 : char mNameAbbrev[16];
11737 0 : char mName[32];
11738 : nsTArray<DR_Rule*> mRules;
11739 0 : private:
11740 0 : DR_FrameTypeInfo& operator=(const DR_FrameTypeInfo&) = delete;
11741 0 : };
11742 0 :
11743 : DR_FrameTypeInfo::DR_FrameTypeInfo(LayoutFrameType aFrameType,
11744 : const char* aFrameNameAbbrev,
11745 : const char* aFrameName)
11746 : {
11747 : mType = aFrameType;
11748 : PL_strncpyz(mNameAbbrev, aFrameNameAbbrev, sizeof(mNameAbbrev));
11749 : PL_strncpyz(mName, aFrameName, sizeof(mName));
11750 : }
11751 :
11752 1 : struct DR_FrameTreeNode
11753 : {
11754 4 : DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent) : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0)
11755 : {
11756 1 : MOZ_COUNT_CTOR(DR_FrameTreeNode);
11757 1 : }
11758 :
11759 1 : ~DR_FrameTreeNode()
11760 : {
11761 1 : MOZ_COUNT_DTOR(DR_FrameTreeNode);
11762 : }
11763 1 :
11764 0 : nsIFrame* mFrame;
11765 0 : DR_FrameTreeNode* mParent;
11766 : bool mDisplay;
11767 : uint32_t mIndent;
11768 : };
11769 :
11770 1 : // DR_State implementation
11771 0 :
11772 0 : DR_State::DR_State()
11773 0 : : mInited(false), mActive(false), mCount(0), mAssert(-1), mIndent(0),
11774 : mIndentUndisplayedFrames(false), mDisplayPixelErrors(false)
11775 : {
11776 : MOZ_COUNT_CTOR(DR_State);
11777 : }
11778 1 :
11779 1 : void DR_State::Init()
11780 0 : {
11781 0 : char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT");
11782 : int32_t num;
11783 : if (env) {
11784 : if (GetNumber(env, num))
11785 : mAssert = num;
11786 1 : else
11787 0 : printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env);
11788 0 : }
11789 0 :
11790 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START");
11791 : if (env) {
11792 : if (GetNumber(env, num))
11793 : mIndent = num;
11794 1 : else
11795 1 : printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env);
11796 1 : }
11797 1 :
11798 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES");
11799 0 : if (env) {
11800 : if (GetNumber(env, num))
11801 0 : mIndentUndisplayedFrames = num;
11802 : else
11803 0 : printf("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s", env);
11804 0 : }
11805 0 :
11806 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS");
11807 0 : if (env) {
11808 0 : if (GetNumber(env, num))
11809 0 : mDisplayPixelErrors = num;
11810 : else
11811 0 : printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s", env);
11812 : }
11813 0 :
11814 : InitFrameTypeTable();
11815 : ParseRulesFile();
11816 0 : mInited = true;
11817 : }
11818 :
11819 0 : DR_State::~DR_State()
11820 : {
11821 : MOZ_COUNT_DTOR(DR_State);
11822 0 : int32_t numElements, i;
11823 0 : numElements = mWildRules.Length();
11824 : for (i = numElements - 1; i >= 0; i--) {
11825 : delete mWildRules.ElementAt(i);
11826 0 : }
11827 : numElements = mFrameTreeLeaves.Length();
11828 : for (i = numElements - 1; i >= 0; i--) {
11829 : delete mFrameTreeLeaves.ElementAt(i);
11830 0 : }
11831 0 : }
11832 :
11833 0 : bool DR_State::GetNumber(char* aBuf,
11834 0 : int32_t& aNumber)
11835 : {
11836 : if (sscanf(aBuf, "%d", &aNumber) > 0)
11837 0 : return true;
11838 0 : else
11839 0 : return false;
11840 : }
11841 :
11842 0 : bool DR_State::IsWhiteSpace(int c) {
11843 0 : return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
11844 0 : }
11845 0 :
11846 0 : bool DR_State::GetToken(FILE* aFile,
11847 : char* aBuf,
11848 : size_t aBufSize)
11849 0 : {
11850 : bool haveToken = false;
11851 : aBuf[0] = 0;
11852 : // get the 1st non whitespace char
11853 0 : int c = -1;
11854 : for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) {
11855 : }
11856 :
11857 0 : if (c > 0) {
11858 : haveToken = true;
11859 0 : aBuf[0] = c;
11860 : // get everything up to the next whitespace char
11861 : size_t cX;
11862 0 : for (cX = 1; cX + 1 < aBufSize ; cX++) {
11863 : c = getc(aFile);
11864 : if (c < 0) { // EOF
11865 : ungetc(' ', aFile);
11866 0 : break;
11867 0 : }
11868 0 : else {
11869 0 : if (IsWhiteSpace(c)) {
11870 0 : break;
11871 0 : }
11872 : else {
11873 : aBuf[cX] = c;
11874 : }
11875 : }
11876 : }
11877 : aBuf[cX] = 0;
11878 0 : }
11879 0 : return haveToken;
11880 : }
11881 0 :
11882 0 : DR_Rule* DR_State::ParseRule(FILE* aFile)
11883 : {
11884 : char buf[128];
11885 0 : int32_t doDisplay;
11886 0 : DR_Rule* rule = nullptr;
11887 0 : while (GetToken(aFile, buf, sizeof(buf))) {
11888 : if (GetNumber(buf, doDisplay)) {
11889 : if (rule) {
11890 : rule->mDisplay = !!doDisplay;
11891 : break;
11892 : }
11893 : else {
11894 : printf("unexpected token - %s \n", buf);
11895 0 : }
11896 : }
11897 : else {
11898 0 : if (!rule) {
11899 : rule = new DR_Rule;
11900 : }
11901 0 : if (strcmp(buf, "*") == 0) {
11902 0 : rule->AddPart(LayoutFrameType::None);
11903 0 : }
11904 0 : else {
11905 0 : DR_FrameTypeInfo* info = GetFrameTypeInfo(buf);
11906 0 : if (info) {
11907 0 : rule->AddPart(info->mType);
11908 : }
11909 : else {
11910 0 : printf("invalid frame type - %s \n", buf);
11911 : }
11912 : }
11913 1 : }
11914 : }
11915 1 : return rule;
11916 1 : }
11917 0 :
11918 0 : void DR_State::AddRule(nsTArray<DR_Rule*>& aRules,
11919 0 : DR_Rule& aRule)
11920 : {
11921 0 : int32_t numRules = aRules.Length();
11922 0 : for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
11923 0 : DR_Rule* rule = aRules.ElementAt(ruleX);
11924 0 : NS_ASSERTION(rule, "program error");
11925 0 : if (aRule.mLength > rule->mLength) {
11926 0 : aRules.InsertElementAt(ruleX, &aRule);
11927 : return;
11928 : }
11929 0 : }
11930 : aRules.AppendElement(&aRule);
11931 0 : }
11932 :
11933 : void DR_State::ParseRulesFile()
11934 : {
11935 0 : char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE");
11936 : if (path) {
11937 1 : FILE* inFile = fopen(path, "r");
11938 : if (!inFile) {
11939 : MOZ_CRASH("Failed to open the specified rules file");
11940 1 : }
11941 : for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
11942 : if (rule->mTarget) {
11943 : LayoutFrameType fType = rule->mTarget->mFrameType;
11944 1 : if (fType != LayoutFrameType::None) {
11945 35 : DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
11946 : AddRule(info->mRules, *rule);
11947 : }
11948 0 : else {
11949 : AddRule(mWildRules, *rule);
11950 0 : }
11951 0 : mActive = true;
11952 0 : }
11953 0 : }
11954 0 :
11955 : fclose(inFile);
11956 : }
11957 : }
11958 0 :
11959 : void
11960 : DR_State::AddFrameTypeInfo(LayoutFrameType aFrameType,
11961 0 : const char* aFrameNameAbbrev,
11962 : const char* aFrameName)
11963 0 : {
11964 0 : mFrameTypeTable.AppendElement(DR_FrameTypeInfo(aFrameType, aFrameNameAbbrev, aFrameName));
11965 0 : }
11966 0 :
11967 0 : DR_FrameTypeInfo*
11968 : DR_State::GetFrameTypeInfo(LayoutFrameType aFrameType)
11969 : {
11970 : int32_t numEntries = mFrameTypeTable.Length();
11971 0 : NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
11972 : for (int32_t i = 0; i < numEntries; i++) {
11973 : DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
11974 1 : if (info.mType == aFrameType) {
11975 : return &info;
11976 1 : }
11977 0 : }
11978 0 : return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
11979 1 : }
11980 1 :
11981 1 : DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName)
11982 1 : {
11983 1 : int32_t numEntries = mFrameTypeTable.Length();
11984 1 : NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
11985 1 : for (int32_t i = 0; i < numEntries; i++) {
11986 1 : DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
11987 1 : if ((strcmp(aFrameName, info.mName) == 0) || (strcmp(aFrameName, info.mNameAbbrev) == 0)) {
11988 1 : return &info;
11989 1 : }
11990 1 : }
11991 1 : return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
11992 1 : }
11993 1 :
11994 1 : void DR_State::InitFrameTypeTable()
11995 1 : {
11996 1 : AddFrameTypeInfo(LayoutFrameType::Block, "block", "block");
11997 1 : AddFrameTypeInfo(LayoutFrameType::Br, "br", "br");
11998 1 : AddFrameTypeInfo(LayoutFrameType::Bullet, "bullet", "bullet");
11999 0 : AddFrameTypeInfo(LayoutFrameType::ColorControl, "color", "colorControl");
12000 1 : AddFrameTypeInfo(LayoutFrameType::GfxButtonControl, "button", "gfxButtonControl");
12001 1 : AddFrameTypeInfo(LayoutFrameType::HTMLButtonControl, "HTMLbutton", "HTMLButtonControl");
12002 0 : AddFrameTypeInfo(LayoutFrameType::HTMLCanvas, "HTMLCanvas","HTMLCanvas");
12003 1 : AddFrameTypeInfo(LayoutFrameType::SubDocument, "subdoc", "subDocument");
12004 1 : AddFrameTypeInfo(LayoutFrameType::Image, "img", "image");
12005 1 : AddFrameTypeInfo(LayoutFrameType::Inline, "inline", "inline");
12006 : AddFrameTypeInfo(LayoutFrameType::Letter, "letter", "letter");
12007 0 : AddFrameTypeInfo(LayoutFrameType::Line, "line", "line");
12008 1 : AddFrameTypeInfo(LayoutFrameType::ListControl, "select", "select");
12009 1 : AddFrameTypeInfo(LayoutFrameType::Object, "obj", "object");
12010 1 : AddFrameTypeInfo(LayoutFrameType::Page, "page", "page");
12011 : AddFrameTypeInfo(LayoutFrameType::Placeholder, "place", "placeholder");
12012 1 : AddFrameTypeInfo(LayoutFrameType::Canvas, "canvas", "canvas");
12013 1 : AddFrameTypeInfo(LayoutFrameType::Root, "root", "root");
12014 : AddFrameTypeInfo(LayoutFrameType::Scroll, "scroll", "scroll");
12015 : AddFrameTypeInfo(LayoutFrameType::TableCell, "cell", "tableCell");
12016 0 : AddFrameTypeInfo(LayoutFrameType::BCTableCell, "bcCell", "bcTableCell");
12017 : AddFrameTypeInfo(LayoutFrameType::TableCol, "col", "tableCol");
12018 : AddFrameTypeInfo(LayoutFrameType::TableColGroup, "colG", "tableColGroup");
12019 0 : AddFrameTypeInfo(LayoutFrameType::Table, "tbl", "table");
12020 0 : AddFrameTypeInfo(LayoutFrameType::TableWrapper, "tblW", "tableWrapper");
12021 0 : AddFrameTypeInfo(LayoutFrameType::TableRowGroup, "rowG", "tableRowGroup");
12022 0 : AddFrameTypeInfo(LayoutFrameType::TableRow, "row", "tableRow");
12023 : AddFrameTypeInfo(LayoutFrameType::TextInput, "textCtl", "textInput");
12024 0 : AddFrameTypeInfo(LayoutFrameType::Text, "text", "text");
12025 0 : AddFrameTypeInfo(LayoutFrameType::Viewport, "VP", "viewport");
12026 0 : #ifdef MOZ_XUL
12027 0 : AddFrameTypeInfo(LayoutFrameType::XULLabel, "XULLabel", "XULLabel");
12028 0 : AddFrameTypeInfo(LayoutFrameType::Box, "Box", "Box");
12029 : AddFrameTypeInfo(LayoutFrameType::Slider, "Slider", "Slider");
12030 : AddFrameTypeInfo(LayoutFrameType::PopupSet, "PopupSet", "PopupSet");
12031 0 : #endif
12032 : AddFrameTypeInfo(LayoutFrameType::None, "unknown", "unknown");
12033 : }
12034 :
12035 0 :
12036 : void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame,
12037 : int32_t aIndent)
12038 0 : {
12039 : DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->Type());
12040 : if (frameTypeInfo) {
12041 0 : for (int32_t i = 0; i < aIndent; i++) {
12042 : printf(" ");
12043 0 : }
12044 : if(!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) {
12045 : if (aFrame) {
12046 : nsAutoString name;
12047 0 : aFrame->GetFrameName(name);
12048 0 : printf("%s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)aFrame);
12049 0 : }
12050 0 : else {
12051 0 : printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
12052 0 : }
12053 : }
12054 : else {
12055 0 : printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
12056 : }
12057 : }
12058 : }
12059 :
12060 : bool
12061 : DR_State::RuleMatches(DR_Rule& aRule, DR_FrameTreeNode& aNode)
12062 0 : {
12063 : NS_ASSERTION(aRule.mTarget, "program error");
12064 0 :
12065 0 : DR_RulePart* rulePart;
12066 0 : DR_FrameTreeNode* parentNode;
12067 : for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent;
12068 : rulePart && parentNode;
12069 0 : rulePart = rulePart->mNext, parentNode = parentNode->mParent) {
12070 : if (rulePart->mFrameType != LayoutFrameType::None) {
12071 0 : if (parentNode->mFrame) {
12072 0 : if (rulePart->mFrameType != parentNode->mFrame->Type()) {
12073 0 : return false;
12074 0 : }
12075 0 : } else NS_ASSERTION(false, "program error");
12076 0 : }
12077 0 : // else wild card match
12078 0 : }
12079 0 : return true;
12080 : }
12081 :
12082 0 : void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode)
12083 0 : {
12084 0 : if (!aNode.mFrame) {
12085 0 : NS_ASSERTION(false, "invalid DR_FrameTreeNode \n");
12086 0 : return;
12087 0 : }
12088 0 :
12089 : bool matchingRule = false;
12090 :
12091 : DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->Type());
12092 : NS_ASSERTION(info, "program error");
12093 : int32_t numRules = info->mRules.Length();
12094 0 : for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
12095 : DR_Rule* rule = info->mRules.ElementAt(ruleX);
12096 : if (rule && RuleMatches(*rule, aNode)) {
12097 : aNode.mDisplay = rule->mDisplay;
12098 : matchingRule = true;
12099 0 : break;
12100 0 : }
12101 0 : }
12102 : if (!matchingRule) {
12103 0 : int32_t numWildRules = mWildRules.Length();
12104 : for (int32_t ruleX = 0; ruleX < numWildRules; ruleX++) {
12105 : DR_Rule* rule = mWildRules.ElementAt(ruleX);
12106 : if (rule && RuleMatches(*rule, aNode)) {
12107 0 : aNode.mDisplay = rule->mDisplay;
12108 : break;
12109 0 : }
12110 0 : }
12111 0 : }
12112 0 : }
12113 0 :
12114 : DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame* aFrame,
12115 : const ReflowInput* aReflowInput)
12116 0 : {
12117 0 : // find the frame of the parent reflow state (usually just the parent of aFrame)
12118 : nsIFrame* parentFrame;
12119 0 : if (aReflowInput) {
12120 0 : const ReflowInput* parentRI = aReflowInput->mParentReflowInput;
12121 0 : parentFrame = (parentRI) ? parentRI->mFrame : nullptr;
12122 : } else {
12123 : parentFrame = aFrame->GetParent();
12124 0 : }
12125 0 :
12126 : // find the parent tree node leaf
12127 0 : DR_FrameTreeNode* parentNode = nullptr;
12128 0 :
12129 : DR_FrameTreeNode* lastLeaf = nullptr;
12130 0 : if(mFrameTreeLeaves.Length())
12131 : lastLeaf = mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Length() - 1);
12132 : if (lastLeaf) {
12133 0 : for (parentNode = lastLeaf; parentNode && (parentNode->mFrame != parentFrame); parentNode = parentNode->mParent) {
12134 : }
12135 : }
12136 : DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode);
12137 0 : FindMatchingRule(*newNode);
12138 :
12139 : newNode->mIndent = mIndent;
12140 : if (newNode->mDisplay || mIndentUndisplayedFrames) {
12141 0 : ++mIndent;
12142 : }
12143 :
12144 : if (lastLeaf && (lastLeaf == parentNode)) {
12145 : mFrameTreeLeaves.RemoveLastElement();
12146 0 : }
12147 : mFrameTreeLeaves.AppendElement(newNode);
12148 : mCount++;
12149 0 :
12150 : return newNode;
12151 0 : }
12152 :
12153 0 : void DR_State::PrettyUC(nscoord aSize,
12154 : char* aBuf,
12155 0 : int aBufSize)
12156 0 : {
12157 0 : if (NS_UNCONSTRAINEDSIZE == aSize) {
12158 0 : strcpy(aBuf, "UC");
12159 0 : }
12160 : else {
12161 : if ((nscoord)0xdeadbeefU == aSize)
12162 : {
12163 : strcpy(aBuf, "deadbeef");
12164 0 : }
12165 : else {
12166 0 : snprintf(aBuf, aBufSize, "%d", aSize);
12167 : }
12168 0 : }
12169 0 : }
12170 0 :
12171 0 : void DR_State::PrintMargin(const char *tag, const nsMargin* aMargin)
12172 : {
12173 : if (aMargin) {
12174 0 : char t[16], r[16], b[16], l[16];
12175 0 : PrettyUC(aMargin->top, t, 16);
12176 : PrettyUC(aMargin->right, r, 16);
12177 : PrettyUC(aMargin->bottom, b, 16);
12178 0 : PrettyUC(aMargin->left, l, 16);
12179 0 : printf(" %s=%s,%s,%s,%s", tag, t, r, b, l);
12180 : } else {
12181 : // use %p here for consistency with other null-pointer printouts
12182 0 : printf(" %s=%p", tag, (void*)aMargin);
12183 : }
12184 : }
12185 0 :
12186 0 : void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode)
12187 : {
12188 : mFrameTreeLeaves.RemoveElement(&aNode);
12189 : int32_t numLeaves = mFrameTreeLeaves.Length();
12190 0 : if ((0 == numLeaves) || (aNode.mParent != mFrameTreeLeaves.ElementAt(numLeaves - 1))) {
12191 : mFrameTreeLeaves.AppendElement(aNode.mParent);
12192 0 : }
12193 :
12194 : if (aNode.mDisplay || mIndentUndisplayedFrames) {
12195 : --mIndent;
12196 : }
12197 : // delete the tree node
12198 0 : delete &aNode;
12199 0 : }
12200 :
12201 : static void
12202 : CheckPixelError(nscoord aSize,
12203 : int32_t aPixelToTwips)
12204 0 : {
12205 0 : if (NS_UNCONSTRAINEDSIZE != aSize) {
12206 0 : if ((aSize % aPixelToTwips) > 0) {
12207 : printf("VALUE %d is not a whole pixel \n", aSize);
12208 0 : }
12209 0 : }
12210 0 : }
12211 :
12212 0 : static void DisplayReflowEnterPrint(nsPresContext* aPresContext,
12213 : nsIFrame* aFrame,
12214 : const ReflowInput& aReflowInput,
12215 0 : DR_FrameTreeNode& aTreeNode,
12216 : bool aChanged)
12217 : {
12218 0 : if (aTreeNode.mDisplay) {
12219 : DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent);
12220 :
12221 0 : char width[16];
12222 : char height[16];
12223 :
12224 0 : DR_state->PrettyUC(aReflowInput.AvailableWidth(), width, 16);
12225 : DR_state->PrettyUC(aReflowInput.AvailableHeight(), height, 16);
12226 : printf("Reflow a=%s,%s ", width, height);
12227 0 :
12228 0 : DR_state->PrettyUC(aReflowInput.ComputedWidth(), width, 16);
12229 : DR_state->PrettyUC(aReflowInput.ComputedHeight(), height, 16);
12230 : printf("c=%s,%s ", width, height);
12231 0 :
12232 0 : if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
12233 : printf("dirty ");
12234 :
12235 0 : if (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)
12236 : printf("dirty-children ");
12237 :
12238 0 : if (aReflowInput.mFlags.mSpecialBSizeReflow)
12239 0 : printf("special-bsize ");
12240 0 :
12241 0 : if (aReflowInput.IsHResize())
12242 0 : printf("h-resize ");
12243 0 :
12244 0 : if (aReflowInput.IsVResize())
12245 : printf("v-resize ");
12246 :
12247 0 : nsIFrame* inFlow = aFrame->GetPrevInFlow();
12248 : if (inFlow) {
12249 279 : printf("pif=%p ", (void*)inFlow);
12250 : }
12251 : inFlow = aFrame->GetNextInFlow();
12252 : if (inFlow) {
12253 279 : printf("nif=%p ", (void*)inFlow);
12254 1 : }
12255 : if (aChanged)
12256 0 : printf("CHANGED \n");
12257 : else
12258 0 : printf("cnt=%d \n", DR_state->mCount);
12259 0 : if (DR_state->mDisplayPixelErrors) {
12260 0 : int32_t p2t = aPresContext->AppUnitsPerDevPixel();
12261 : CheckPixelError(aReflowInput.AvailableWidth(), p2t);
12262 : CheckPixelError(aReflowInput.AvailableHeight(), p2t);
12263 : CheckPixelError(aReflowInput.ComputedWidth(), p2t);
12264 : CheckPixelError(aReflowInput.ComputedHeight(), p2t);
12265 395 : }
12266 : }
12267 1 : }
12268 1 :
12269 : void* nsFrame::DisplayReflowEnter(nsPresContext* aPresContext,
12270 0 : nsIFrame* aFrame,
12271 : const ReflowInput& aReflowInput)
12272 0 : {
12273 0 : if (!DR_state->mInited) DR_state->Init();
12274 0 : if (!DR_state->mActive) return nullptr;
12275 :
12276 : NS_ASSERTION(aFrame, "invalid call");
12277 :
12278 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowInput);
12279 : if (treeNode) {
12280 1 : DisplayReflowEnterPrint(aPresContext, aFrame, aReflowInput, *treeNode, false);
12281 : }
12282 : return treeNode;
12283 1 : }
12284 182 :
12285 : void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame)
12286 0 : {
12287 : if (!DR_state->mInited) DR_state->Init();
12288 0 : if (!DR_state->mActive) return nullptr;
12289 0 :
12290 0 : NS_ASSERTION(aFrame, "invalid call");
12291 :
12292 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
12293 : if (treeNode && treeNode->mDisplay) {
12294 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12295 : printf("XULLayout\n");
12296 3888 : }
12297 : return treeNode;
12298 : }
12299 3888 :
12300 1 : void* nsFrame::DisplayIntrinsicISizeEnter(nsIFrame* aFrame,
12301 : const char* aType)
12302 0 : {
12303 : if (!DR_state->mInited) DR_state->Init();
12304 0 : if (!DR_state->mActive) return nullptr;
12305 0 :
12306 0 : NS_ASSERTION(aFrame, "invalid call");
12307 :
12308 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
12309 : if (treeNode && treeNode->mDisplay) {
12310 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12311 : printf("Get%sWidth\n", aType);
12312 279 : }
12313 : return treeNode;
12314 : }
12315 :
12316 : void* nsFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame,
12317 : const char* aType)
12318 1 : {
12319 : if (!DR_state->mInited) DR_state->Init();
12320 0 : if (!DR_state->mActive) return nullptr;
12321 0 :
12322 : NS_ASSERTION(aFrame, "invalid call");
12323 0 :
12324 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
12325 0 : if (treeNode && treeNode->mDisplay) {
12326 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12327 : printf("Get%sSize\n", aType);
12328 : }
12329 : return treeNode;
12330 : }
12331 0 :
12332 0 : void nsFrame::DisplayReflowExit(nsPresContext* aPresContext,
12333 0 : nsIFrame* aFrame,
12334 : ReflowOutput& aMetrics,
12335 0 : const nsReflowStatus& aStatus,
12336 0 : void* aFrameTreeNode)
12337 : {
12338 0 : if (!DR_state->mActive) return;
12339 0 :
12340 0 : NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call");
12341 0 : if (!aFrameTreeNode) return;
12342 0 :
12343 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
12344 : if (treeNode->mDisplay) {
12345 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12346 0 :
12347 0 : char width[16];
12348 0 : char height[16];
12349 0 : char x[16];
12350 0 : char y[16];
12351 : DR_state->PrettyUC(aMetrics.Width(), width, 16);
12352 0 : DR_state->PrettyUC(aMetrics.Height(), height, 16);
12353 0 : printf("Reflow d=%s,%s", width, height);
12354 0 :
12355 0 : if (!aStatus.IsEmpty()) {
12356 0 : printf(" status=%s", ToString(aStatus).c_str());
12357 : }
12358 0 : if (aFrame->HasOverflowAreas()) {
12359 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().x, x, 16);
12360 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().y, y, 16);
12361 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().width, width, 16);
12362 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().height, height, 16);
12363 0 : printf(" vis-o=(%s,%s) %s x %s", x, y, width, height);
12364 :
12365 0 : nsRect storedOverflow = aFrame->GetVisualOverflowRect();
12366 0 : DR_state->PrettyUC(storedOverflow.x, x, 16);
12367 0 : DR_state->PrettyUC(storedOverflow.y, y, 16);
12368 0 : DR_state->PrettyUC(storedOverflow.width, width, 16);
12369 0 : DR_state->PrettyUC(storedOverflow.height, height, 16);
12370 : printf(" vis-sto=(%s,%s) %s x %s", x, y, width, height);
12371 :
12372 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().x, x, 16);
12373 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().y, y, 16);
12374 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().width, width, 16);
12375 395 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().height, height, 16);
12376 : printf(" scr-o=(%s,%s) %s x %s", x, y, width, height);
12377 :
12378 395 : storedOverflow = aFrame->GetScrollableOverflowRect();
12379 : DR_state->PrettyUC(storedOverflow.x, x, 16);
12380 0 : DR_state->PrettyUC(storedOverflow.y, y, 16);
12381 0 : DR_state->PrettyUC(storedOverflow.width, width, 16);
12382 : DR_state->PrettyUC(storedOverflow.height, height, 16);
12383 0 : printf(" scr-sto=(%s,%s) %s x %s", x, y, width, height);
12384 0 : }
12385 0 : printf("\n");
12386 0 : if (DR_state->mDisplayPixelErrors) {
12387 0 : int32_t p2t = aPresContext->AppUnitsPerDevPixel();
12388 : CheckPixelError(aMetrics.Width(), p2t);
12389 0 : CheckPixelError(aMetrics.Height(), p2t);
12390 : }
12391 : }
12392 182 : DR_state->DeleteTreeNode(*treeNode);
12393 : }
12394 :
12395 : void nsFrame::DisplayLayoutExit(nsIFrame* aFrame,
12396 : void* aFrameTreeNode)
12397 1 : {
12398 : if (!DR_state->mActive) return;
12399 0 :
12400 0 : NS_ASSERTION(aFrame, "non-null frame required");
12401 : if (!aFrameTreeNode) return;
12402 0 :
12403 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
12404 0 : if (treeNode->mDisplay) {
12405 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12406 0 : nsRect rect = aFrame->GetRect();
12407 0 : printf("XULLayout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
12408 : }
12409 0 : DR_state->DeleteTreeNode(*treeNode);
12410 : }
12411 :
12412 1 : void nsFrame::DisplayIntrinsicISizeExit(nsIFrame* aFrame,
12413 : const char* aType,
12414 : nscoord aResult,
12415 : void* aFrameTreeNode)
12416 : {
12417 1 : if (!DR_state->mActive) return;
12418 :
12419 0 : NS_ASSERTION(aFrame, "non-null frame required");
12420 0 : if (!aFrameTreeNode) return;
12421 :
12422 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
12423 0 : if (treeNode->mDisplay) {
12424 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12425 : char width[16];
12426 : DR_state->PrettyUC(aResult, width, 16);
12427 : printf("Get%sWidth=%s\n", aType, width);
12428 0 : }
12429 0 : DR_state->DeleteTreeNode(*treeNode);
12430 0 : }
12431 :
12432 0 : void nsFrame::DisplayIntrinsicSizeExit(nsIFrame* aFrame,
12433 : const char* aType,
12434 : nsSize aResult,
12435 : void* aFrameTreeNode)
12436 1 : {
12437 : if (!DR_state->mActive) return;
12438 1 :
12439 1 : NS_ASSERTION(aFrame, "non-null frame required");
12440 : if (!aFrameTreeNode) return;
12441 :
12442 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
12443 : if (treeNode->mDisplay) {
12444 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12445 0 :
12446 0 : char width[16];
12447 : char height[16];
12448 0 : DR_state->PrettyUC(aResult.width, width, 16);
12449 : DR_state->PrettyUC(aResult.height, height, 16);
12450 0 : printf("Get%sSize=%s,%s\n", aType, width, height);
12451 0 : }
12452 0 : DR_state->DeleteTreeNode(*treeNode);
12453 : }
12454 0 :
12455 : /* static */ void
12456 : nsFrame::DisplayReflowStartup()
12457 307 : {
12458 : DR_state = new DR_State();
12459 : }
12460 :
12461 : /* static */ void
12462 : nsFrame::DisplayReflowShutdown()
12463 : {
12464 1 : delete DR_state;
12465 1 : DR_state = nullptr;
12466 : }
12467 307 :
12468 1 : void DR_cookie::Change() const
12469 : {
12470 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue;
12471 0 : if (treeNode && treeNode->mDisplay) {
12472 0 : DisplayReflowEnterPrint(mPresContext, mFrame, mReflowInput, *treeNode, true);
12473 : }
12474 : }
12475 0 :
12476 : /* static */ void*
12477 : ReflowInput::DisplayInitConstraintsEnter(nsIFrame* aFrame,
12478 : ReflowInput* aState,
12479 : nscoord aContainingBlockWidth,
12480 0 : nscoord aContainingBlockHeight,
12481 0 : const nsMargin* aBorder,
12482 0 : const nsMargin* aPadding)
12483 : {
12484 0 : MOZ_ASSERT(aFrame, "non-null frame required");
12485 0 : MOZ_ASSERT(aState, "non-null state required");
12486 0 :
12487 : if (!DR_state->mInited) DR_state->Init();
12488 0 : if (!DR_state->mActive) return nullptr;
12489 0 :
12490 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aState);
12491 : if (treeNode && treeNode->mDisplay) {
12492 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12493 :
12494 : printf("InitConstraints parent=%p",
12495 : (void*)aState->mParentReflowInput);
12496 307 :
12497 : char width[16];
12498 : char height[16];
12499 :
12500 0 : DR_state->PrettyUC(aContainingBlockWidth, width, 16);
12501 0 : DR_state->PrettyUC(aContainingBlockHeight, height, 16);
12502 : printf(" cb=%s,%s", width, height);
12503 307 :
12504 0 : DR_state->PrettyUC(aState->AvailableWidth(), width, 16);
12505 : DR_state->PrettyUC(aState->AvailableHeight(), height, 16);
12506 0 : printf(" as=%s,%s", width, height);
12507 0 :
12508 0 : DR_state->PrintMargin("b", aBorder);
12509 : DR_state->PrintMargin("p", aPadding);
12510 0 : putchar('\n');
12511 0 : }
12512 0 : return treeNode;
12513 0 : }
12514 0 :
12515 0 : /* static */ void
12516 : ReflowInput::DisplayInitConstraintsExit(nsIFrame* aFrame,
12517 0 : ReflowInput* aState,
12518 0 : void* aValue)
12519 0 : {
12520 : MOZ_ASSERT(aFrame, "non-null frame required");
12521 0 : MOZ_ASSERT(aState, "non-null state required");
12522 :
12523 : if (!DR_state->mActive) return;
12524 : if (!aValue) return;
12525 :
12526 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
12527 : if (treeNode->mDisplay) {
12528 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12529 : char cmiw[16], cw[16], cmxw[16], cmih[16], ch[16], cmxh[16];
12530 : DR_state->PrettyUC(aState->ComputedMinWidth(), cmiw, 16);
12531 : DR_state->PrettyUC(aState->ComputedWidth(), cw, 16);
12532 : DR_state->PrettyUC(aState->ComputedMaxWidth(), cmxw, 16);
12533 1 : DR_state->PrettyUC(aState->ComputedMinHeight(), cmih, 16);
12534 1 : DR_state->PrettyUC(aState->ComputedHeight(), ch, 16);
12535 : DR_state->PrettyUC(aState->ComputedMaxHeight(), cmxh, 16);
12536 307 : printf("InitConstraints= cw=(%s <= %s <= %s) ch=(%s <= %s <= %s)",
12537 1 : cmiw, cw, cmxw, cmih, ch, cmxh);
12538 : DR_state->PrintMargin("co", &aState->ComputedPhysicalOffsets());
12539 : putchar('\n');
12540 0 : }
12541 0 : DR_state->DeleteTreeNode(*treeNode);
12542 0 : }
12543 :
12544 :
12545 0 : /* static */ void*
12546 0 : SizeComputationInput::DisplayInitOffsetsEnter(nsIFrame* aFrame,
12547 : SizeComputationInput* aState,
12548 0 : nscoord aPercentBasis,
12549 0 : WritingMode aCBWritingMode,
12550 0 : const nsMargin* aBorder,
12551 : const nsMargin* aPadding)
12552 : {
12553 : MOZ_ASSERT(aFrame, "non-null frame required");
12554 : MOZ_ASSERT(aState, "non-null state required");
12555 :
12556 307 : if (!DR_state->mInited) DR_state->Init();
12557 : if (!DR_state->mActive) return nullptr;
12558 :
12559 : // aState is not necessarily a ReflowInput
12560 307 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
12561 307 : if (treeNode && treeNode->mDisplay) {
12562 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12563 0 :
12564 0 : char pctBasisStr[16];
12565 : DR_state->PrettyUC(aPercentBasis, pctBasisStr, 16);
12566 0 : printf("InitOffsets pct_basis=%s", pctBasisStr);
12567 0 :
12568 0 : DR_state->PrintMargin("b", aBorder);
12569 0 : DR_state->PrintMargin("p", aPadding);
12570 0 : putchar('\n');
12571 0 : }
12572 0 : return treeNode;
12573 0 : }
12574 :
12575 0 : /* static */ void
12576 : SizeComputationInput::DisplayInitOffsetsExit(nsIFrame* aFrame,
12577 : SizeComputationInput* aState,
12578 : void* aValue)
12579 1 : {
12580 : MOZ_ASSERT(aFrame, "non-null frame required");
12581 : MOZ_ASSERT(aState, "non-null state required");
12582 307 :
12583 1 : if (!DR_state->mActive) return;
12584 : if (!aValue) return;
12585 307 :
12586 307 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
12587 : if (treeNode->mDisplay) {
12588 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12589 0 : printf("InitOffsets=");
12590 : DR_state->PrintMargin("m", &aState->ComputedPhysicalMargin());
12591 : DR_state->PrintMargin("p", &aState->ComputedPhysicalPadding());
12592 : DR_state->PrintMargin("p+b", &aState->ComputedPhysicalBorderPadding());
12593 307 : putchar('\n');
12594 : }
12595 : DR_state->DeleteTreeNode(*treeNode);
12596 : }
12597 307 :
12598 0 : /* static */ void*
12599 : ReflowInput::DisplayInitFrameTypeEnter(nsIFrame* aFrame,
12600 307 : ReflowInput* aState)
12601 0 : {
12602 : MOZ_ASSERT(aFrame, "non-null frame required");
12603 0 : MOZ_ASSERT(aState, "non-null state required");
12604 0 :
12605 0 : if (!DR_state->mInited) DR_state->Init();
12606 0 : if (!DR_state->mActive) return nullptr;
12607 :
12608 0 : // we don't print anything here
12609 : return DR_state->CreateTreeNode(aFrame, aState);
12610 0 : }
12611 :
12612 0 : /* static */ void
12613 : ReflowInput::DisplayInitFrameTypeExit(nsIFrame* aFrame,
12614 0 : ReflowInput* aState,
12615 : void* aValue)
12616 0 : {
12617 : MOZ_ASSERT(aFrame, "non-null frame required");
12618 : MOZ_ASSERT(aState, "non-null state required");
12619 :
12620 0 : if (!DR_state->mActive) return;
12621 0 : if (!aValue) return;
12622 0 :
12623 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
12624 : if (treeNode->mDisplay) {
12625 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
12626 : printf("InitFrameType");
12627 :
12628 : const nsStyleDisplay *disp = aState->mStyleDisplay;
12629 :
12630 0 : if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
12631 0 : printf(" out-of-flow");
12632 0 : if (aFrame->GetPrevInFlow())
12633 0 : printf(" prev-in-flow");
12634 : if (aFrame->IsAbsolutelyPositioned())
12635 0 : printf(" abspos");
12636 : if (aFrame->IsFloating())
12637 : printf(" float");
12638 0 :
12639 : const nsCSSKeyword displayVal =
12640 0 : nsCSSProps::ValueToKeywordEnum(disp->mDisplay,
12641 : nsCSSProps::kDisplayKTable);
12642 0 : if (displayVal == eCSSKeyword_UNKNOWN)
12643 : printf(" display=%u", static_cast<uint32_t>(disp->mDisplay));
12644 : else
12645 : printf(" display=%s", nsCSSKeywords::GetStringValue(displayVal).get());
12646 :
12647 : // This array must exactly match the NS_CSS_FRAME_TYPE constants.
12648 : const char *const cssFrameTypes[] = {
12649 : "unknown", "inline", "block", "floating", "absolute", "internal-table"
12650 : };
12651 : nsCSSFrameType bareType = NS_FRAME_GET_TYPE(aState->mFrameType);
12652 : bool repNoBlock = NS_FRAME_IS_REPLACED_NOBLOCK(aState->mFrameType);
12653 : bool repBlock = NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(aState->mFrameType);
12654 :
12655 : if (bareType >= ArrayLength(cssFrameTypes)) {
12656 : printf(" result=type %u", bareType);
12657 : } else {
12658 : printf(" result=%s", cssFrameTypes[bareType]);
12659 : }
12660 : printf("%s%s\n", repNoBlock ? " +rep" : "", repBlock ? " +repBlk" : "");
12661 : }
12662 : DR_state->DeleteTreeNode(*treeNode);
12663 : }
12664 :
12665 : #endif
12666 : // End Display Reflow
12667 :
12668 : #endif
|