Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : // vim:cindent:ts=2:et:sw=2:
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/DebugOnly.h"
18 : #include "mozilla/gfx/2D.h"
19 : #include "mozilla/gfx/PathHelpers.h"
20 : #include "mozilla/Sprintf.h"
21 :
22 : #include "nsCOMPtr.h"
23 : #include "nsFrameList.h"
24 : #include "nsPlaceholderFrame.h"
25 : #include "nsIContent.h"
26 : #include "nsIContentInlines.h"
27 : #include "nsContentUtils.h"
28 : #include "nsCSSPseudoElements.h"
29 : #include "nsIAtom.h"
30 : #include "nsString.h"
31 : #include "nsReadableUtils.h"
32 : #include "nsStyleContext.h"
33 : #include "nsTableWrapperFrame.h"
34 : #include "nsView.h"
35 : #include "nsViewManager.h"
36 : #include "nsIScrollableFrame.h"
37 : #include "nsPresContext.h"
38 : #include "nsStyleConsts.h"
39 : #include "nsIPresShell.h"
40 : #include "mozilla/Logging.h"
41 : #include "mozilla/Sprintf.h"
42 : #include "nsFrameManager.h"
43 : #include "nsLayoutUtils.h"
44 : #include "LayoutLogging.h"
45 : #include "mozilla/GeckoStyleContext.h"
46 : #include "mozilla/GeckoRestyleManager.h"
47 : #include "mozilla/RestyleManager.h"
48 : #include "mozilla/RestyleManagerInlines.h"
49 : #include "nsInlineFrame.h"
50 : #include "nsIDOMNode.h"
51 : #include "nsISelection.h"
52 : #include "nsISelectionPrivate.h"
53 : #include "nsFrameSelection.h"
54 : #include "nsGkAtoms.h"
55 : #include "nsCSSAnonBoxes.h"
56 :
57 : #include "nsFrameTraversal.h"
58 : #include "nsRange.h"
59 : #include "nsITextControlFrame.h"
60 : #include "nsNameSpaceManager.h"
61 : #include "nsIPercentBSizeObserver.h"
62 : #include "nsStyleStructInlines.h"
63 : #include "FrameLayerBuilder.h"
64 : #include "ImageLayers.h"
65 :
66 : #include "nsBidiPresUtils.h"
67 : #include "RubyUtils.h"
68 : #include "nsAnimationManager.h"
69 :
70 : // For triple-click pref
71 : #include "imgIContainer.h"
72 : #include "imgIRequest.h"
73 : #include "nsError.h"
74 : #include "nsContainerFrame.h"
75 : #include "nsBoxLayoutState.h"
76 : #include "nsBlockFrame.h"
77 : #include "nsDisplayList.h"
78 : #include "nsSVGIntegrationUtils.h"
79 : #include "nsSVGEffects.h"
80 : #include "nsChangeHint.h"
81 : #include "nsDeckFrame.h"
82 : #include "nsSubDocumentFrame.h"
83 : #include "SVGTextFrame.h"
84 :
85 : #include "gfxContext.h"
86 : #include "nsAbsoluteContainingBlock.h"
87 : #include "StickyScrollContainer.h"
88 : #include "nsFontInflationData.h"
89 : #include "nsRegion.h"
90 : #include "nsIFrameInlines.h"
91 : #include "nsStyleChangeList.h"
92 :
93 : #include "mozilla/AsyncEventDispatcher.h"
94 : #include "mozilla/EffectCompositor.h"
95 : #include "mozilla/EffectSet.h"
96 : #include "mozilla/EventListenerManager.h"
97 : #include "mozilla/EventStateManager.h"
98 : #include "mozilla/EventStates.h"
99 : #include "mozilla/Preferences.h"
100 : #include "mozilla/LookAndFeel.h"
101 : #include "mozilla/MouseEvents.h"
102 : #include "mozilla/ServoStyleSet.h"
103 : #include "mozilla/css/ImageLoader.h"
104 : #include "mozilla/gfx/Tools.h"
105 : #include "nsPrintfCString.h"
106 : #include "ActiveLayerTracker.h"
107 :
108 : #include "nsITheme.h"
109 : #include "nsThemeConstants.h"
110 :
111 : using namespace mozilla;
112 : using namespace mozilla::css;
113 : using namespace mozilla::dom;
114 : using namespace mozilla::gfx;
115 : using namespace mozilla::layers;
116 : using namespace mozilla::layout;
117 : typedef nsAbsoluteContainingBlock::AbsPosReflowFlags AbsPosReflowFlags;
118 :
119 : const mozilla::LayoutFrameType nsIFrame::sLayoutFrameTypes[
120 : #define FRAME_ID(...) 1 +
121 : #define ABSTRACT_FRAME_ID(...)
122 : #include "nsFrameIdList.h"
123 : #undef FRAME_ID
124 : #undef ABSTRACT_FRAME_ID
125 : 0] = {
126 : #define FRAME_ID(class_, type_, ...) mozilla::LayoutFrameType:: type_,
127 : #define ABSTRACT_FRAME_ID(...)
128 : #include "nsFrameIdList.h"
129 : #undef FRAME_ID
130 : #undef ABSTRACT_FRAME_ID
131 : };
132 :
133 : const nsIFrame::FrameClassBits nsIFrame::sFrameClassBits[
134 : #define FRAME_ID(...) 1 +
135 : #define ABSTRACT_FRAME_ID(...)
136 : #include "nsFrameIdList.h"
137 : #undef FRAME_ID
138 : #undef ABSTRACT_FRAME_ID
139 : 0] = {
140 : #define Leaf eFrameClassBitsLeaf
141 : #define NotLeaf eFrameClassBitsNone
142 : #define DynamicLeaf eFrameClassBitsDynamicLeaf
143 : #define FRAME_ID(class_, type_, leaf_, ...) leaf_,
144 : #define ABSTRACT_FRAME_ID(...)
145 : #include "nsFrameIdList.h"
146 : #undef Leaf
147 : #undef NotLeaf
148 : #undef DynamicLeaf
149 : #undef FRAME_ID
150 : #undef ABSTRACT_FRAME_ID
151 : };
152 :
153 : // Struct containing cached metrics for box-wrapped frames.
154 67 : struct nsBoxLayoutMetrics
155 : {
156 : nsSize mPrefSize;
157 : nsSize mMinSize;
158 : nsSize mMaxSize;
159 :
160 : nsSize mBlockMinSize;
161 : nsSize mBlockPrefSize;
162 : nscoord mBlockAscent;
163 :
164 : nscoord mFlex;
165 : nscoord mAscent;
166 :
167 : nsSize mLastSize;
168 : };
169 :
170 : struct nsContentAndOffset
171 : {
172 : nsIContent* mContent;
173 : int32_t mOffset;
174 : };
175 :
176 : // Some Misc #defines
177 : #define SELECTION_DEBUG 0
178 : #define FORCE_SELECTION_UPDATE 1
179 : #define CALC_DEBUG 0
180 :
181 : // This is faster than nsBidiPresUtils::IsFrameInParagraphDirection,
182 : // because it uses the frame pointer passed in without drilling down to
183 : // the leaf frame.
184 : static bool
185 0 : IsReversedDirectionFrame(nsIFrame* aFrame)
186 : {
187 0 : FrameBidiData bidiData = aFrame->GetBidiData();
188 0 : return !IS_SAME_DIRECTION(bidiData.embeddingLevel, bidiData.baseLevel);
189 : }
190 :
191 : #include "nsILineIterator.h"
192 :
193 : //non Hack prototypes
194 : #if 0
195 : static void RefreshContentFrames(nsPresContext* aPresContext, nsIContent * aStartContent, nsIContent * aEndContent);
196 : #endif
197 :
198 : #include "prenv.h"
199 :
200 1489 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(BoxMetricsProperty, nsBoxLayoutMetrics)
201 :
202 : static void
203 67 : InitBoxMetrics(nsIFrame* aFrame, bool aClear)
204 : {
205 67 : if (aClear) {
206 7 : aFrame->DeleteProperty(BoxMetricsProperty());
207 : }
208 :
209 67 : nsBoxLayoutMetrics* metrics = new nsBoxLayoutMetrics();
210 67 : aFrame->SetProperty(BoxMetricsProperty(), metrics);
211 :
212 67 : static_cast<nsFrame*>(aFrame)->nsFrame::MarkIntrinsicISizesDirty();
213 67 : metrics->mBlockAscent = 0;
214 67 : metrics->mLastSize.SizeTo(0, 0);
215 67 : }
216 :
217 : static bool
218 2706 : IsXULBoxWrapped(const nsIFrame* aFrame)
219 : {
220 5207 : return aFrame->GetParent() &&
221 4088 : aFrame->GetParent()->IsXULBoxFrame() &&
222 4088 : !aFrame->IsXULBoxFrame();
223 : }
224 :
225 : void
226 575 : nsReflowStatus::UpdateTruncated(const ReflowInput& aReflowInput,
227 : const ReflowOutput& aMetrics)
228 : {
229 575 : const WritingMode containerWM = aMetrics.GetWritingMode();
230 575 : if (aReflowInput.GetWritingMode().IsOrthogonalTo(containerWM)) {
231 : // Orthogonal flows are always reflowed with an unconstrained dimension,
232 : // so should never end up truncated (see ReflowInput::Init()).
233 0 : mTruncated = false;
234 1150 : } else if (aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE &&
235 575 : aReflowInput.AvailableBSize() < aMetrics.BSize(containerWM) &&
236 0 : !aReflowInput.mFlags.mIsTopOfPage) {
237 0 : mTruncated = true;
238 : } else {
239 575 : mTruncated = false;
240 : }
241 575 : }
242 :
243 : // Formerly the nsIFrameDebug interface
244 :
245 : #ifdef DEBUG
246 0 : std::ostream& operator<<(std::ostream& aStream,
247 : const nsReflowStatus& aStatus)
248 : {
249 0 : char complete = 'Y';
250 0 : if (aStatus.IsIncomplete()) {
251 0 : complete = 'N';
252 0 : } else if (aStatus.IsOverflowIncomplete()) {
253 0 : complete = 'O';
254 : }
255 :
256 0 : char brk = 'N';
257 0 : if (aStatus.IsInlineBreakBefore()) {
258 0 : brk = 'B';
259 0 : } else if (aStatus.IsInlineBreakAfter()) {
260 0 : brk = 'A';
261 : }
262 :
263 : aStream << "["
264 : << "Complete=" << complete << ","
265 0 : << "NIF=" << (aStatus.NextInFlowNeedsReflow() ? 'Y' : 'N') << ","
266 0 : << "Truncated=" << (aStatus.IsTruncated() ? 'Y' : 'N') << ","
267 : << "Break=" << brk << ","
268 0 : << "FirstLetter=" << (aStatus.FirstLetterComplete() ? 'Y' : 'N')
269 0 : << "]";
270 0 : return aStream;
271 : }
272 :
273 : static bool gShowFrameBorders = false;
274 :
275 0 : void nsFrame::ShowFrameBorders(bool aEnable)
276 : {
277 0 : gShowFrameBorders = aEnable;
278 0 : }
279 :
280 3113 : bool nsFrame::GetShowFrameBorders()
281 : {
282 3113 : return gShowFrameBorders;
283 : }
284 :
285 : static bool gShowEventTargetFrameBorder = false;
286 :
287 0 : void nsFrame::ShowEventTargetFrameBorder(bool aEnable)
288 : {
289 0 : gShowEventTargetFrameBorder = aEnable;
290 0 : }
291 :
292 3123 : bool nsFrame::GetShowEventTargetFrameBorder()
293 : {
294 3123 : return gShowEventTargetFrameBorder;
295 : }
296 :
297 : /**
298 : * Note: the log module is created during library initialization which
299 : * means that you cannot perform logging before then.
300 : */
301 : mozilla::LazyLogModule nsFrame::sFrameLogModule("frame");
302 :
303 : static mozilla::LazyLogModule sStyleVerifyTreeLogModuleInfo("styleverifytree");
304 :
305 : static uint32_t gStyleVerifyTreeEnable = 0x55;
306 :
307 : bool
308 836 : nsFrame::GetVerifyStyleTreeEnable()
309 : {
310 836 : if (gStyleVerifyTreeEnable == 0x55) {
311 2 : gStyleVerifyTreeEnable = 0 != (int)((mozilla::LogModule*)sStyleVerifyTreeLogModuleInfo)->Level();
312 : }
313 836 : return gStyleVerifyTreeEnable;
314 : }
315 :
316 : void
317 0 : nsFrame::SetVerifyStyleTreeEnable(bool aEnabled)
318 : {
319 0 : gStyleVerifyTreeEnable = aEnabled;
320 0 : }
321 :
322 : #endif
323 :
324 1383 : NS_DECLARE_FRAME_PROPERTY_DELETABLE(AbsoluteContainingBlockProperty,
325 : nsAbsoluteContainingBlock)
326 :
327 : bool
328 1229 : nsIFrame::HasAbsolutelyPositionedChildren() const {
329 1229 : return IsAbsoluteContainer() && GetAbsoluteContainingBlock()->HasAbsoluteFrames();
330 : }
331 :
332 : nsAbsoluteContainingBlock*
333 1251 : nsIFrame::GetAbsoluteContainingBlock() const {
334 1251 : NS_ASSERTION(IsAbsoluteContainer(), "The frame is not marked as an abspos container correctly");
335 1251 : nsAbsoluteContainingBlock* absCB = GetProperty(AbsoluteContainingBlockProperty());
336 1251 : NS_ASSERTION(absCB, "The frame is marked as an abspos container but doesn't have the property");
337 1251 : return absCB;
338 : }
339 :
340 : void
341 64 : nsIFrame::MarkAsAbsoluteContainingBlock()
342 : {
343 64 : MOZ_ASSERT(GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
344 64 : NS_ASSERTION(!GetProperty(AbsoluteContainingBlockProperty()),
345 : "Already has an abs-pos containing block property?");
346 64 : NS_ASSERTION(!HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
347 : "Already has NS_FRAME_HAS_ABSPOS_CHILDREN state bit?");
348 64 : AddStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
349 128 : SetProperty(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID()));
350 64 : }
351 :
352 : void
353 2 : nsIFrame::MarkAsNotAbsoluteContainingBlock()
354 : {
355 2 : NS_ASSERTION(!HasAbsolutelyPositionedChildren(), "Think of the children!");
356 2 : NS_ASSERTION(GetProperty(AbsoluteContainingBlockProperty()),
357 : "Should have an abs-pos containing block property");
358 2 : NS_ASSERTION(HasAnyStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN),
359 : "Should have NS_FRAME_HAS_ABSPOS_CHILDREN state bit");
360 2 : MOZ_ASSERT(HasAnyStateBits(NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN));
361 2 : RemoveStateBits(NS_FRAME_HAS_ABSPOS_CHILDREN);
362 2 : DeleteProperty(AbsoluteContainingBlockProperty());
363 2 : }
364 :
365 : bool
366 0 : nsIFrame::CheckAndClearPaintedState()
367 : {
368 0 : bool result = (GetStateBits() & NS_FRAME_PAINTED_THEBES);
369 0 : RemoveStateBits(NS_FRAME_PAINTED_THEBES);
370 :
371 0 : nsIFrame::ChildListIterator lists(this);
372 0 : for (; !lists.IsDone(); lists.Next()) {
373 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
374 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
375 0 : nsIFrame* child = childFrames.get();
376 0 : if (child->CheckAndClearPaintedState()) {
377 0 : result = true;
378 : }
379 : }
380 : }
381 0 : return result;
382 : }
383 :
384 : bool
385 4 : nsIFrame::IsVisibleConsideringAncestors(uint32_t aFlags) const
386 : {
387 4 : if (!StyleVisibility()->IsVisible()) {
388 0 : return false;
389 : }
390 :
391 4 : const nsIFrame* frame = this;
392 124 : while (frame) {
393 64 : nsView* view = frame->GetView();
394 64 : if (view && view->GetVisibility() == nsViewVisibility_kHide)
395 0 : return false;
396 :
397 64 : nsIFrame* parent = frame->GetParent();
398 64 : nsDeckFrame* deck = do_QueryFrame(parent);
399 64 : if (deck) {
400 12 : if (deck->GetSelectedBox() != frame)
401 0 : return false;
402 : }
403 :
404 64 : if (parent) {
405 60 : frame = parent;
406 : } else {
407 4 : parent = nsLayoutUtils::GetCrossDocParentFrame(frame);
408 4 : if (!parent)
409 4 : break;
410 :
411 0 : if ((aFlags & nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) == 0 &&
412 0 : parent->PresContext()->IsChrome() && !frame->PresContext()->IsChrome()) {
413 0 : break;
414 : }
415 :
416 0 : if (!parent->StyleVisibility()->IsVisible())
417 0 : return false;
418 :
419 0 : frame = parent;
420 : }
421 : }
422 :
423 4 : return true;
424 : }
425 :
426 : void
427 0 : nsIFrame::FindCloserFrameForSelection(
428 : nsPoint aPoint,
429 : nsIFrame::FrameWithDistance* aCurrentBestFrame)
430 : {
431 0 : if (nsLayoutUtils::PointIsCloserToRect(aPoint, mRect,
432 : aCurrentBestFrame->mXDistance,
433 : aCurrentBestFrame->mYDistance)) {
434 0 : aCurrentBestFrame->mFrame = this;
435 : }
436 0 : }
437 :
438 : void
439 45 : nsIFrame::ContentStatesChanged(mozilla::EventStates aStates)
440 : {
441 45 : }
442 :
443 4 : AutoWeakFrame::AutoWeakFrame(const WeakFrame& aOther)
444 4 : : mPrev(nullptr), mFrame(nullptr)
445 : {
446 4 : Init(aOther.GetFrame());
447 4 : }
448 :
449 : void
450 139 : AutoWeakFrame::Init(nsIFrame* aFrame)
451 : {
452 139 : Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
453 139 : mFrame = aFrame;
454 139 : if (mFrame) {
455 118 : nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
456 118 : NS_WARNING_ASSERTION(shell, "Null PresShell in AutoWeakFrame!");
457 118 : if (shell) {
458 118 : shell->AddAutoWeakFrame(this);
459 : } else {
460 0 : mFrame = nullptr;
461 : }
462 : }
463 139 : }
464 :
465 : void
466 270 : WeakFrame::Init(nsIFrame* aFrame)
467 : {
468 270 : Clear(mFrame ? mFrame->PresContext()->GetPresShell() : nullptr);
469 270 : mFrame = aFrame;
470 270 : if (mFrame) {
471 41 : nsIPresShell* shell = mFrame->PresContext()->GetPresShell();
472 41 : MOZ_ASSERT(shell, "Null PresShell in WeakFrame!");
473 41 : if (shell) {
474 41 : shell->AddWeakFrame(this);
475 : } else {
476 0 : mFrame = nullptr;
477 : }
478 : }
479 270 : }
480 :
481 : nsIFrame*
482 0 : NS_NewEmptyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
483 : {
484 0 : return new (aPresShell) nsFrame(aContext);
485 : }
486 :
487 666 : nsFrame::nsFrame(nsStyleContext* aContext, ClassID aID)
488 666 : : nsBox(aID)
489 : {
490 666 : MOZ_COUNT_CTOR(nsFrame);
491 :
492 666 : mStyleContext = aContext;
493 666 : mWritingMode = WritingMode(mStyleContext);
494 666 : mStyleContext->AddRef();
495 : #ifdef DEBUG
496 666 : mStyleContext->FrameAddRef();
497 : #endif
498 666 : }
499 :
500 252 : nsFrame::~nsFrame()
501 : {
502 126 : MOZ_COUNT_DTOR(nsFrame);
503 :
504 126 : MOZ_ASSERT(GetVisibility() != Visibility::APPROXIMATELY_VISIBLE,
505 : "Visible nsFrame is being destroyed");
506 :
507 126 : NS_IF_RELEASE(mContent);
508 : #ifdef DEBUG
509 126 : mStyleContext->FrameRelease();
510 : #endif
511 126 : mStyleContext->Release();
512 126 : }
513 :
514 0 : NS_IMPL_FRAMEARENA_HELPERS(nsFrame)
515 :
516 : // Dummy operator delete. Will never be called, but must be defined
517 : // to satisfy some C++ ABIs.
518 : void
519 0 : nsFrame::operator delete(void *, size_t)
520 : {
521 0 : MOZ_CRASH("nsFrame::operator delete should never be called");
522 : }
523 :
524 7629 : NS_QUERYFRAME_HEAD(nsFrame)
525 138 : NS_QUERYFRAME_ENTRY(nsIFrame)
526 7491 : NS_QUERYFRAME_TAIL_INHERITANCE_ROOT
527 :
528 : /////////////////////////////////////////////////////////////////////////////
529 : // nsIFrame
530 :
531 : static bool
532 666 : IsFontSizeInflationContainer(nsIFrame* aFrame,
533 : const nsStyleDisplay* aStyleDisplay)
534 : {
535 : /*
536 : * Font size inflation is built around the idea that we're inflating
537 : * the fonts for a pan-and-zoom UI so that when the user scales up a
538 : * block or other container to fill the width of the device, the fonts
539 : * will be readable. To do this, we need to pick what counts as a
540 : * container.
541 : *
542 : * From a code perspective, the only hard requirement is that frames
543 : * that are line participants
544 : * (nsIFrame::IsFrameOfType(nsIFrame::eLineParticipant)) are never
545 : * containers, since line layout assumes that the inflation is
546 : * consistent within a line.
547 : *
548 : * This is not an imposition, since we obviously want a bunch of text
549 : * (possibly with inline elements) flowing within a block to count the
550 : * block (or higher) as its container.
551 : *
552 : * We also want form controls, including the text in the anonymous
553 : * content inside of them, to match each other and the text next to
554 : * them, so they and their anonymous content should also not be a
555 : * container.
556 : *
557 : * However, because we can't reliably compute sizes across XUL during
558 : * reflow, any XUL frame with a XUL parent is always a container.
559 : *
560 : * There are contexts where it would be nice if some blocks didn't
561 : * count as a container, so that, for example, an indented quotation
562 : * didn't end up with a smaller font size. However, it's hard to
563 : * distinguish these situations where we really do want the indented
564 : * thing to count as a container, so we don't try, and blocks are
565 : * always containers.
566 : */
567 :
568 : // The root frame should always be an inflation container.
569 666 : if (!aFrame->GetParent()) {
570 24 : return true;
571 : }
572 :
573 642 : nsIContent *content = aFrame->GetContent();
574 642 : LayoutFrameType frameType = aFrame->Type();
575 1077 : bool isInline = (aFrame->GetDisplay() == StyleDisplay::Inline ||
576 870 : RubyUtils::IsRubyBox(frameType) ||
577 435 : (aFrame->IsFloating() &&
578 435 : frameType == LayoutFrameType::Letter) ||
579 : // Given multiple frames for the same node, only the
580 : // outer one should be considered a container.
581 : // (Important, e.g., for nsSelectsAreaFrame.)
582 796 : (aFrame->GetParent()->GetContent() == content) ||
583 361 : (content && (content->IsAnyOfHTMLElements(nsGkAtoms::option,
584 : nsGkAtoms::optgroup,
585 361 : nsGkAtoms::select) ||
586 1601 : content->IsInNativeAnonymousSubtree()))) &&
587 983 : !(aFrame->IsXULBoxFrame() && aFrame->GetParent()->IsXULBoxFrame());
588 642 : NS_ASSERTION(!aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
589 : isInline ||
590 : // br frames and mathml frames report being line
591 : // participants even when their position or display is
592 : // set
593 : aFrame->IsBrFrame() ||
594 : aFrame->IsFrameOfType(nsIFrame::eMathML),
595 : "line participants must not be containers");
596 642 : NS_ASSERTION(!aFrame->IsBulletFrame() || isInline,
597 : "bullets should not be containers");
598 642 : return !isInline;
599 : }
600 :
601 : void
602 666 : nsFrame::Init(nsIContent* aContent,
603 : nsContainerFrame* aParent,
604 : nsIFrame* aPrevInFlow)
605 : {
606 666 : MOZ_ASSERT(nsQueryFrame::FrameIID(mClass) == GetFrameId());
607 666 : NS_PRECONDITION(!mContent, "Double-initing a frame?");
608 666 : NS_ASSERTION(IsFrameOfType(eDEBUGAllFrames) &&
609 : !IsFrameOfType(eDEBUGNoFrames),
610 : "IsFrameOfType implementation that doesn't call base class");
611 :
612 666 : mContent = aContent;
613 666 : mParent = aParent;
614 :
615 666 : if (aContent) {
616 642 : NS_ADDREF(aContent);
617 : }
618 :
619 666 : if (aPrevInFlow) {
620 0 : mWritingMode = aPrevInFlow->GetWritingMode();
621 :
622 : // Make sure the general flags bits are the same
623 0 : nsFrameState state = aPrevInFlow->GetStateBits();
624 :
625 : // Make bits that are currently off (see constructor) the same:
626 : mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
627 : NS_FRAME_PART_OF_IBSPLIT |
628 : NS_FRAME_MAY_BE_TRANSFORMED |
629 : NS_FRAME_MAY_HAVE_GENERATED_CONTENT |
630 0 : NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN);
631 : } else {
632 666 : PresContext()->ConstructedFrame();
633 : }
634 666 : if (GetParent()) {
635 642 : nsFrameState state = GetParent()->GetStateBits();
636 :
637 : // Make bits that are currently off (see constructor) the same:
638 : mState |= state & (NS_FRAME_INDEPENDENT_SELECTION |
639 : NS_FRAME_GENERATED_CONTENT |
640 : NS_FRAME_IS_SVG_TEXT |
641 : NS_FRAME_IN_POPUP |
642 642 : NS_FRAME_IS_NONDISPLAY);
643 :
644 642 : if (HasAnyStateBits(NS_FRAME_IN_POPUP) && TrackingVisibility()) {
645 : // Assume all frames in popups are visible.
646 0 : IncApproximateVisibleCount();
647 : }
648 : }
649 666 : const nsStyleDisplay *disp = StyleDisplay();
650 1332 : if (disp->HasTransform(this) ||
651 1316 : (IsFrameOfType(eSupportsCSSTransforms) &&
652 658 : nsLayoutUtils::HasAnimationOfProperty(this, eCSSProperty_transform))) {
653 : // The frame gets reconstructed if we toggle the -moz-transform
654 : // property, so we can set this bit here and then ignore it.
655 8 : mState |= NS_FRAME_MAY_BE_TRANSFORMED;
656 : }
657 1332 : if (disp->mPosition == NS_STYLE_POSITION_STICKY &&
658 0 : !aPrevInFlow &&
659 666 : !(mState & NS_FRAME_IS_NONDISPLAY) &&
660 0 : !disp->IsInnerTableStyle()) {
661 : // Note that we only add first continuations, but we really only
662 : // want to add first continuation-or-ib-split-siblings. But since we
663 : // don't yet know if we're a later part of a block-in-inline split,
664 : // we'll just add later members of a block-in-inline split here, and
665 : // then StickyScrollContainer will remove them later.
666 : // We don't currently support relative positioning of inner table
667 : // elements (bug 35168), so exclude them from sticky positioning too.
668 : StickyScrollContainer* ssc =
669 0 : StickyScrollContainer::GetStickyScrollContainerForFrame(this);
670 0 : if (ssc) {
671 0 : ssc->AddFrame(this);
672 : }
673 : }
674 :
675 1332 : if (nsLayoutUtils::FontSizeInflationEnabled(PresContext()) || !GetParent()
676 : #ifdef DEBUG
677 : // We have assertions that check inflation invariants even when
678 : // font size inflation is not enabled.
679 666 : || true
680 : #endif
681 : ) {
682 666 : if (IsFontSizeInflationContainer(this, disp)) {
683 379 : AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER);
684 1113 : if (!GetParent() ||
685 : // I'd use NS_FRAME_OUT_OF_FLOW, but it's not set yet.
686 734 : disp->IsFloating(this) || disp->IsAbsolutelyPositioned(this)) {
687 31 : AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
688 : }
689 : }
690 666 : NS_ASSERTION(GetParent() ||
691 : (GetStateBits() & NS_FRAME_FONT_INFLATION_CONTAINER),
692 : "root frame should always be a container");
693 : }
694 :
695 1319 : if (PresContext()->PresShell()->AssumeAllFramesVisible() &&
696 653 : TrackingVisibility()) {
697 0 : IncApproximateVisibleCount();
698 : }
699 :
700 666 : DidSetStyleContext(nullptr);
701 :
702 666 : if (::IsXULBoxWrapped(this))
703 60 : ::InitBoxMetrics(this, false);
704 666 : }
705 :
706 : void
707 126 : nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
708 : {
709 126 : NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(),
710 : "destroy called on frame while scripts not blocked");
711 126 : NS_ASSERTION(!GetNextSibling() && !GetPrevSibling(),
712 : "Frames should be removed before destruction.");
713 126 : NS_ASSERTION(aDestructRoot, "Must specify destruct root");
714 126 : MOZ_ASSERT(!HasAbsolutelyPositionedChildren());
715 126 : MOZ_ASSERT(!HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT),
716 : "NS_FRAME_PART_OF_IBSPLIT set on non-nsContainerFrame?");
717 :
718 126 : nsSVGEffects::InvalidateDirectRenderingObservers(this);
719 :
720 126 : if (StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) {
721 : StickyScrollContainer* ssc =
722 0 : StickyScrollContainer::GetStickyScrollContainerForFrame(this);
723 0 : if (ssc) {
724 0 : ssc->RemoveFrame(this);
725 : }
726 : }
727 :
728 126 : nsPresContext* presContext = PresContext();
729 126 : nsIPresShell* shell = presContext->GetPresShell();
730 126 : if (mState & NS_FRAME_OUT_OF_FLOW) {
731 8 : nsPlaceholderFrame* placeholder = GetPlaceholderFrame();
732 8 : NS_ASSERTION(!placeholder || (aDestructRoot != this),
733 : "Don't call Destroy() on OOFs, call Destroy() on the placeholder.");
734 8 : NS_ASSERTION(!placeholder ||
735 : nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, placeholder),
736 : "Placeholder relationship should have been torn down already; "
737 : "this might mean we have a stray placeholder in the tree.");
738 8 : if (placeholder) {
739 0 : placeholder->SetOutOfFlowFrame(nullptr);
740 : }
741 : }
742 :
743 126 : bool isPrimaryFrame = (mContent && mContent->GetPrimaryFrame() == this);
744 126 : if (isPrimaryFrame) {
745 : // This needs to happen before we clear our Properties() table.
746 111 : ActiveLayerTracker::TransferActivityToContent(this, mContent);
747 :
748 : // Unfortunately, we need to do this for all frames being reframed
749 : // and not only those whose current style involves CSS transitions,
750 : // because what matters is whether the new style (not the old)
751 : // specifies CSS transitions.
752 111 : if (presContext->RestyleManager()->IsGecko()) {
753 : // stylo: ServoRestyleManager does not handle transitions yet, and when
754 : // it does it probably won't need to track reframed style contexts to
755 : // initiate transitions correctly.
756 : GeckoRestyleManager::ReframingStyleContexts* rsc =
757 111 : presContext->RestyleManager()->AsGecko()->GetReframingStyleContexts();
758 111 : if (rsc) {
759 106 : rsc->Put(mContent, mStyleContext);
760 : }
761 : }
762 : }
763 :
764 250 : if (HasCSSAnimations() || HasCSSTransitions() ||
765 124 : EffectSet::GetEffectSet(this)) {
766 : // If no new frame for this element is created by the end of the
767 : // restyling process, stop animations and transitions for this frame
768 : RestyleManager::AnimationsWithDestroyedFrame* adf =
769 2 : presContext->RestyleManager()->GetAnimationsWithDestroyedFrame();
770 : // AnimationsWithDestroyedFrame only lives during the restyling process.
771 2 : if (adf) {
772 2 : adf->Put(mContent, mStyleContext);
773 : }
774 : }
775 :
776 : // Disable visibility tracking. Note that we have to do this before we clear
777 : // frame properties and lose track of whether we were previously visible.
778 : // XXX(seth): It'd be ideal to assert that we're already marked nonvisible
779 : // here, but it's unfortunately tricky to guarantee in the face of things like
780 : // frame reconstruction induced by style changes.
781 126 : DisableVisibilityTracking();
782 :
783 : // Ensure that we're not in the approximately visible list anymore.
784 126 : PresContext()->GetPresShell()->RemoveFrameFromApproximatelyVisibleList(this);
785 :
786 126 : shell->NotifyDestroyingFrame(this);
787 :
788 126 : if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
789 5 : shell->ClearFrameRefs(this);
790 : }
791 :
792 126 : nsView* view = GetView();
793 126 : if (view) {
794 9 : view->SetFrame(nullptr);
795 9 : view->Destroy();
796 : }
797 :
798 : // Make sure that our deleted frame can't be returned from GetPrimaryFrame()
799 126 : if (isPrimaryFrame) {
800 111 : mContent->SetPrimaryFrame(nullptr);
801 : }
802 :
803 : // Delete all properties attached to the frame, to ensure any property
804 : // destructors that need the frame pointer are handled properly.
805 126 : DeleteAllProperties();
806 :
807 : // Must retrieve the object ID before calling destructors, so the
808 : // vtable is still valid.
809 : //
810 : // Note to future tweakers: having the method that returns the
811 : // object size call the destructor will not avoid an indirect call;
812 : // the compiler cannot devirtualize the call to the destructor even
813 : // if it's from a method defined in the same class.
814 :
815 126 : nsQueryFrame::FrameIID id = GetFrameId();
816 126 : this->~nsFrame();
817 :
818 : // Now that we're totally cleaned out, we need to add ourselves to
819 : // the presshell's recycler.
820 126 : shell->FreeFrame(id, this);
821 126 : }
822 :
823 : nsresult
824 0 : nsFrame::GetOffsets(int32_t &aStart, int32_t &aEnd) const
825 : {
826 0 : aStart = 0;
827 0 : aEnd = 0;
828 0 : return NS_OK;
829 : }
830 :
831 : static
832 : void
833 2622 : AddAndRemoveImageAssociations(nsFrame* aFrame,
834 : const nsStyleImageLayers* aOldLayers,
835 : const nsStyleImageLayers* aNewLayers)
836 : {
837 : ImageLoader* imageLoader =
838 2622 : aFrame->PresContext()->Document()->StyleImageLoader();
839 :
840 : // If the old context had a background-image image, or mask-image image,
841 : // and new context does not have the same image, clear the image load
842 : // notifier (which keeps the image loading, if it still is) for the frame.
843 : // We want to do this conservatively because some frames paint their
844 : // backgrounds from some other frame's style data, and we don't want
845 : // to clear those notifiers unless we have to. (They'll be reset
846 : // when we paint, although we could miss a notification in that
847 : // interval.)
848 :
849 2622 : if (aOldLayers) {
850 2640 : NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aOldLayers)) {
851 : // If there is an image in oldBG that's not in newBG, drop it.
852 2656 : if (i >= aNewLayers->mImageCount ||
853 1328 : !aOldLayers->mLayers[i].mImage.ImageDataEquals(
854 1328 : aNewLayers->mLayers[i].mImage)) {
855 1292 : const nsStyleImage& oldImage = aOldLayers->mLayers[i].mImage;
856 1292 : if (oldImage.GetType() != eStyleImageType_Image) {
857 1292 : continue;
858 : }
859 :
860 0 : if (aFrame->HasImageRequest()) {
861 0 : if (imgRequestProxy* req = oldImage.GetImageData()) {
862 0 : imageLoader->DisassociateRequestFromFrame(req, aFrame);
863 : }
864 : }
865 : }
866 : }
867 : }
868 :
869 5264 : NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, (*aNewLayers)) {
870 : // If there is an image in newBG that's not in oldBG, add it.
871 3970 : if (!aOldLayers || i >= aOldLayers->mImageCount ||
872 1328 : !aNewLayers->mLayers[i].mImage.ImageDataEquals(
873 1328 : aOldLayers->mLayers[i].mImage)) {
874 2606 : const nsStyleImage& newImage = aNewLayers->mLayers[i].mImage;
875 2606 : if (newImage.GetType() != eStyleImageType_Image) {
876 2594 : continue;
877 : }
878 :
879 12 : if (imgRequestProxy* req = newImage.GetImageData()) {
880 12 : imageLoader->AssociateRequestToFrame(req, aFrame);
881 : }
882 : }
883 : }
884 2622 : }
885 :
886 : // Subclass hook for style post processing
887 : /* virtual */ void
888 1311 : nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
889 : {
890 1311 : if (nsSVGUtils::IsInSVGTextSubtree(this)) {
891 : SVGTextFrame* svgTextFrame = static_cast<SVGTextFrame*>(
892 0 : nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::SVGText));
893 0 : nsIFrame* anonBlock = svgTextFrame->PrincipalChildList().FirstChild();
894 : // Just as in SVGTextFrame::DidSetStyleContext, we need to ensure that
895 : // any non-display SVGTextFrames get reflowed when a child text frame
896 : // gets new style.
897 : //
898 : // Note that we must check NS_FRAME_FIRST_REFLOW on our SVGTextFrame's
899 : // anonymous block frame rather than our self, since NS_FRAME_FIRST_REFLOW
900 : // may be set on us if we're a new frame that has been inserted after the
901 : // document's first reflow. (In which case this DidSetStyleContext call may
902 : // be happening under frame construction under a Reflow() call.)
903 0 : if (anonBlock && !(anonBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
904 0 : (svgTextFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY) &&
905 0 : !(svgTextFrame->GetStateBits() & NS_STATE_SVG_TEXT_IN_REFLOW)) {
906 0 : svgTextFrame->ScheduleReflowSVGNonDisplayText(nsIPresShell::eStyleChange);
907 : }
908 : }
909 :
910 1967 : const nsStyleImageLayers *oldLayers = aOldStyleContext ?
911 656 : &aOldStyleContext->StyleBackground()->mImage :
912 1311 : nullptr;
913 1311 : const nsStyleImageLayers *newLayers = &StyleBackground()->mImage;
914 1311 : AddAndRemoveImageAssociations(this, oldLayers, newLayers);
915 :
916 1311 : oldLayers = aOldStyleContext ? &aOldStyleContext->StyleSVGReset()->mMask :
917 : nullptr;
918 1311 : newLayers = &StyleSVGReset()->mMask;
919 1311 : AddAndRemoveImageAssociations(this, oldLayers, newLayers);
920 :
921 1311 : if (aOldStyleContext) {
922 : // If we detect a change on margin, padding or border, we store the old
923 : // values on the frame itself between now and reflow, so if someone
924 : // calls GetUsed(Margin|Border|Padding)() before the next reflow, we
925 : // can give an accurate answer.
926 : // We don't want to set the property if one already exists.
927 656 : nsMargin oldValue(0, 0, 0, 0);
928 656 : nsMargin newValue(0, 0, 0, 0);
929 656 : const nsStyleMargin* oldMargin = aOldStyleContext->PeekStyleMargin();
930 656 : if (oldMargin && oldMargin->GetMargin(oldValue)) {
931 461 : if ((!StyleMargin()->GetMargin(newValue) || oldValue != newValue) &&
932 0 : !HasProperty(UsedMarginProperty())) {
933 0 : AddProperty(UsedMarginProperty(), new nsMargin(oldValue));
934 : }
935 : }
936 :
937 656 : const nsStylePadding* oldPadding = aOldStyleContext->PeekStylePadding();
938 656 : if (oldPadding && oldPadding->GetPadding(oldValue)) {
939 417 : if ((!StylePadding()->GetPadding(newValue) || oldValue != newValue) &&
940 0 : !HasProperty(UsedPaddingProperty())) {
941 0 : AddProperty(UsedPaddingProperty(), new nsMargin(oldValue));
942 : }
943 : }
944 :
945 656 : const nsStyleBorder* oldBorder = aOldStyleContext->PeekStyleBorder();
946 656 : if (oldBorder) {
947 655 : oldValue = oldBorder->GetComputedBorder();
948 655 : newValue = StyleBorder()->GetComputedBorder();
949 655 : if (oldValue != newValue &&
950 0 : !HasProperty(UsedBorderProperty())) {
951 0 : AddProperty(UsedBorderProperty(), new nsMargin(oldValue));
952 : }
953 : }
954 : }
955 :
956 1311 : ImageLoader* imageLoader = PresContext()->Document()->StyleImageLoader();
957 : imgIRequest *oldBorderImage = aOldStyleContext
958 1311 : ? aOldStyleContext->StyleBorder()->GetBorderImageRequest()
959 1311 : : nullptr;
960 1311 : imgIRequest *newBorderImage = StyleBorder()->GetBorderImageRequest();
961 : // FIXME (Bug 759996): The following is no longer true.
962 : // For border-images, we can't be as conservative (we need to set the
963 : // new loaders if there has been any change) since the CalcDifference
964 : // call depended on the result of GetComputedBorder() and that result
965 : // depends on whether the image has loaded, start the image load now
966 : // so that we'll get notified when it completes loading and can do a
967 : // restyle. Otherwise, the image might finish loading from the
968 : // network before we start listening to its notifications, and then
969 : // we'll never know that it's finished loading. Likewise, we want to
970 : // do this for freshly-created frames to prevent a similar race if the
971 : // image loads between reflow (which can depend on whether the image
972 : // is loaded) and paint. We also don't really care about any callers
973 : // who try to paint borders with a different style context, because
974 : // they won't have the correct size for the border either.
975 1311 : if (oldBorderImage != newBorderImage) {
976 : // stop and restart the image loading/notification
977 0 : if (oldBorderImage && HasImageRequest()) {
978 0 : imageLoader->DisassociateRequestFromFrame(oldBorderImage, this);
979 : }
980 0 : if (newBorderImage) {
981 0 : imageLoader->AssociateRequestToFrame(newBorderImage, this);
982 : }
983 : }
984 :
985 : // If the page contains markup that overrides text direction, and
986 : // does not contain any characters that would activate the Unicode
987 : // bidi algorithm, we need to call |SetBidiEnabled| on the pres
988 : // context before reflow starts. See bug 115921.
989 1311 : if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) {
990 0 : PresContext()->SetBidiEnabled();
991 : }
992 :
993 1311 : RemoveStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS |
994 1311 : NS_FRAME_SIMPLE_DISPLAYLIST);
995 :
996 1311 : mMayHaveRoundedCorners = true;
997 1311 : }
998 :
999 : void
1000 3 : nsIFrame::ReparentFrameViewTo(nsViewManager* aViewManager,
1001 : nsView* aNewParentView,
1002 : nsView* aOldParentView)
1003 : {
1004 3 : if (HasView()) {
1005 : #ifdef MOZ_XUL
1006 0 : if (IsMenuPopupFrame()) {
1007 : // This view must be parented by the root view, don't reparent it.
1008 0 : return;
1009 : }
1010 : #endif
1011 0 : nsView* view = GetView();
1012 : // Verify that the current parent view is what we think it is
1013 : //nsView* parentView;
1014 : //NS_ASSERTION(parentView == aOldParentView, "unexpected parent view");
1015 :
1016 0 : aViewManager->RemoveChild(view);
1017 :
1018 : // The view will remember the Z-order and other attributes that have been set on it.
1019 0 : nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(aNewParentView, this);
1020 0 : aViewManager->InsertChild(aNewParentView, view, insertBefore, insertBefore != nullptr);
1021 3 : } else if (GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW) {
1022 0 : nsIFrame::ChildListIterator lists(this);
1023 0 : for (; !lists.IsDone(); lists.Next()) {
1024 : // Iterate the child frames, and check each child frame to see if it has
1025 : // a view
1026 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
1027 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
1028 0 : childFrames.get()->ReparentFrameViewTo(aViewManager, aNewParentView,
1029 0 : aOldParentView);
1030 : }
1031 : }
1032 : }
1033 : }
1034 :
1035 : void
1036 135 : nsIFrame::SyncFrameViewProperties(nsView* aView)
1037 : {
1038 135 : if (!aView) {
1039 108 : aView = GetView();
1040 108 : if (!aView) {
1041 101 : return;
1042 : }
1043 : }
1044 :
1045 34 : nsViewManager* vm = aView->GetViewManager();
1046 :
1047 : // Make sure visibility is correct. This only affects nsSubDocumentFrame.
1048 34 : if (!SupportsVisibilityHidden()) {
1049 : // See if the view should be hidden or visible
1050 3 : nsStyleContext* sc = StyleContext();
1051 3 : vm->SetViewVisibility(aView,
1052 3 : sc->StyleVisibility()->IsVisible()
1053 3 : ? nsViewVisibility_kShow : nsViewVisibility_kHide);
1054 : }
1055 :
1056 34 : int32_t zIndex = 0;
1057 34 : bool autoZIndex = false;
1058 :
1059 34 : if (IsAbsPosContainingBlock()) {
1060 : // Make sure z-index is correct
1061 0 : nsStyleContext* sc = StyleContext();
1062 0 : const nsStylePosition* position = sc->StylePosition();
1063 0 : if (position->mZIndex.GetUnit() == eStyleUnit_Integer) {
1064 0 : zIndex = position->mZIndex.GetIntValue();
1065 0 : } else if (position->mZIndex.GetUnit() == eStyleUnit_Auto) {
1066 0 : autoZIndex = true;
1067 : }
1068 : } else {
1069 34 : autoZIndex = true;
1070 : }
1071 :
1072 34 : vm->SetViewZIndex(aView, autoZIndex, zIndex);
1073 : }
1074 :
1075 : void
1076 3 : nsFrame::CreateView()
1077 : {
1078 3 : MOZ_ASSERT(!HasView());
1079 :
1080 3 : nsView* parentView = GetParent()->GetClosestView();
1081 3 : MOZ_ASSERT(parentView, "no parent with view");
1082 :
1083 3 : nsViewManager* viewManager = parentView->GetViewManager();
1084 3 : MOZ_ASSERT(viewManager, "null view manager");
1085 :
1086 3 : nsView* view = viewManager->CreateView(GetRect(), parentView);
1087 3 : SyncFrameViewProperties(view);
1088 :
1089 3 : nsView* insertBefore = nsLayoutUtils::FindSiblingViewFor(parentView, this);
1090 : // we insert this view 'above' the insertBefore view, unless insertBefore is null,
1091 : // in which case we want to call with aAbove == false to insert at the beginning
1092 : // in document order
1093 3 : viewManager->InsertChild(parentView, view, insertBefore, insertBefore != nullptr);
1094 :
1095 : // REVIEW: Don't create a widget for fixed-pos elements anymore.
1096 : // ComputeRepaintRegionForCopy will calculate the right area to repaint
1097 : // when we scroll.
1098 : // Reparent views on any child frames (or their descendants) to this
1099 : // view. We can just call ReparentFrameViewTo on this frame because
1100 : // we know this frame has no view, so it will crawl the children. Also,
1101 : // we know that any descendants with views must have 'parentView' as their
1102 : // parent view.
1103 3 : ReparentFrameViewTo(viewManager, view, parentView);
1104 :
1105 : // Remember our view
1106 3 : SetView(view);
1107 :
1108 3 : NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
1109 : ("nsFrame::CreateView: frame=%p view=%p",
1110 : this, view));
1111 3 : }
1112 :
1113 : // MSVC fails with link error "one or more multiply defined symbols found",
1114 : // gcc fails with "hidden symbol `nsIFrame::kPrincipalList' isn't defined"
1115 : // etc if they are not defined.
1116 : #ifndef _MSC_VER
1117 : // static nsIFrame constants; initialized in the header file.
1118 : const nsIFrame::ChildListID nsIFrame::kPrincipalList;
1119 : const nsIFrame::ChildListID nsIFrame::kAbsoluteList;
1120 : const nsIFrame::ChildListID nsIFrame::kBulletList;
1121 : const nsIFrame::ChildListID nsIFrame::kCaptionList;
1122 : const nsIFrame::ChildListID nsIFrame::kColGroupList;
1123 : const nsIFrame::ChildListID nsIFrame::kExcessOverflowContainersList;
1124 : const nsIFrame::ChildListID nsIFrame::kFixedList;
1125 : const nsIFrame::ChildListID nsIFrame::kFloatList;
1126 : const nsIFrame::ChildListID nsIFrame::kOverflowContainersList;
1127 : const nsIFrame::ChildListID nsIFrame::kOverflowList;
1128 : const nsIFrame::ChildListID nsIFrame::kOverflowOutOfFlowList;
1129 : const nsIFrame::ChildListID nsIFrame::kPopupList;
1130 : const nsIFrame::ChildListID nsIFrame::kPushedFloatsList;
1131 : const nsIFrame::ChildListID nsIFrame::kSelectPopupList;
1132 : const nsIFrame::ChildListID nsIFrame::kNoReflowPrincipalList;
1133 : #endif
1134 :
1135 : /* virtual */ nsMargin
1136 142 : nsIFrame::GetUsedMargin() const
1137 : {
1138 142 : nsMargin margin(0, 0, 0, 0);
1139 284 : if (((mState & NS_FRAME_FIRST_REFLOW) &&
1140 284 : !(mState & NS_FRAME_IN_REFLOW)) ||
1141 142 : nsSVGUtils::IsInSVGTextSubtree(this))
1142 0 : return margin;
1143 :
1144 142 : nsMargin *m = GetProperty(UsedMarginProperty());
1145 142 : if (m) {
1146 0 : margin = *m;
1147 : } else {
1148 142 : if (!StyleMargin()->GetMargin(margin)) {
1149 : // If we get here, our caller probably shouldn't be calling us...
1150 0 : NS_ERROR("Returning bogus 0-sized margin, because this margin "
1151 : "depends on layout & isn't cached!");
1152 : }
1153 : }
1154 142 : return margin;
1155 : }
1156 :
1157 : /* virtual */ nsMargin
1158 1737 : nsIFrame::GetUsedBorder() const
1159 : {
1160 1737 : nsMargin border(0, 0, 0, 0);
1161 3496 : if (((mState & NS_FRAME_FIRST_REFLOW) &&
1162 3474 : !(mState & NS_FRAME_IN_REFLOW)) ||
1163 1737 : nsSVGUtils::IsInSVGTextSubtree(this))
1164 0 : return border;
1165 :
1166 : // Theme methods don't use const-ness.
1167 1737 : nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
1168 :
1169 1737 : const nsStyleDisplay *disp = StyleDisplay();
1170 1737 : if (mutable_this->IsThemed(disp)) {
1171 61 : nsIntMargin result;
1172 61 : nsPresContext *presContext = PresContext();
1173 122 : presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
1174 61 : mutable_this, disp->mAppearance,
1175 122 : &result);
1176 61 : border.left = presContext->DevPixelsToAppUnits(result.left);
1177 61 : border.top = presContext->DevPixelsToAppUnits(result.top);
1178 61 : border.right = presContext->DevPixelsToAppUnits(result.right);
1179 61 : border.bottom = presContext->DevPixelsToAppUnits(result.bottom);
1180 61 : return border;
1181 : }
1182 :
1183 1676 : nsMargin *b = GetProperty(UsedBorderProperty());
1184 1676 : if (b) {
1185 0 : border = *b;
1186 : } else {
1187 1676 : border = StyleBorder()->GetComputedBorder();
1188 : }
1189 1676 : return border;
1190 : }
1191 :
1192 : /* virtual */ nsMargin
1193 704 : nsIFrame::GetUsedPadding() const
1194 : {
1195 704 : nsMargin padding(0, 0, 0, 0);
1196 1430 : if (((mState & NS_FRAME_FIRST_REFLOW) &&
1197 1408 : !(mState & NS_FRAME_IN_REFLOW)) ||
1198 704 : nsSVGUtils::IsInSVGTextSubtree(this))
1199 0 : return padding;
1200 :
1201 : // Theme methods don't use const-ness.
1202 704 : nsIFrame *mutable_this = const_cast<nsIFrame*>(this);
1203 :
1204 704 : const nsStyleDisplay *disp = StyleDisplay();
1205 704 : if (mutable_this->IsThemed(disp)) {
1206 4 : nsPresContext *presContext = PresContext();
1207 4 : nsIntMargin widget;
1208 8 : if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
1209 : mutable_this,
1210 4 : disp->mAppearance,
1211 4 : &widget)) {
1212 0 : padding.top = presContext->DevPixelsToAppUnits(widget.top);
1213 0 : padding.right = presContext->DevPixelsToAppUnits(widget.right);
1214 0 : padding.bottom = presContext->DevPixelsToAppUnits(widget.bottom);
1215 0 : padding.left = presContext->DevPixelsToAppUnits(widget.left);
1216 0 : return padding;
1217 : }
1218 : }
1219 :
1220 704 : nsMargin *p = GetProperty(UsedPaddingProperty());
1221 704 : if (p) {
1222 1 : padding = *p;
1223 : } else {
1224 703 : if (!StylePadding()->GetPadding(padding)) {
1225 : // If we get here, our caller probably shouldn't be calling us...
1226 0 : NS_ERROR("Returning bogus 0-sized padding, because this padding "
1227 : "depends on layout & isn't cached!");
1228 : }
1229 : }
1230 704 : return padding;
1231 : }
1232 :
1233 : nsIFrame::Sides
1234 2236 : nsIFrame::GetSkipSides(const ReflowInput* aReflowInput) const
1235 : {
1236 4472 : if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
1237 2236 : StyleBoxDecorationBreak::Clone) &&
1238 0 : !(GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1239 0 : return Sides();
1240 : }
1241 :
1242 : // Convert the logical skip sides to physical sides using the frame's
1243 : // writing mode
1244 2236 : WritingMode writingMode = GetWritingMode();
1245 2236 : LogicalSides logicalSkip = GetLogicalSkipSides(aReflowInput);
1246 2236 : Sides skip;
1247 :
1248 2236 : if (logicalSkip.BStart()) {
1249 0 : if (writingMode.IsVertical()) {
1250 0 : skip |= writingMode.IsVerticalLR() ? eSideBitsLeft : eSideBitsRight;
1251 : } else {
1252 0 : skip |= eSideBitsTop;
1253 : }
1254 : }
1255 :
1256 2236 : if (logicalSkip.BEnd()) {
1257 0 : if (writingMode.IsVertical()) {
1258 0 : skip |= writingMode.IsVerticalLR() ? eSideBitsRight : eSideBitsLeft;
1259 : } else {
1260 0 : skip |= eSideBitsBottom;
1261 : }
1262 : }
1263 :
1264 2236 : if (logicalSkip.IStart()) {
1265 0 : if (writingMode.IsVertical()) {
1266 0 : skip |= eSideBitsTop;
1267 : } else {
1268 0 : skip |= writingMode.IsBidiLTR() ? eSideBitsLeft : eSideBitsRight;
1269 : }
1270 : }
1271 :
1272 2236 : if (logicalSkip.IEnd()) {
1273 0 : if (writingMode.IsVertical()) {
1274 0 : skip |= eSideBitsBottom;
1275 : } else {
1276 0 : skip |= writingMode.IsBidiLTR() ? eSideBitsRight : eSideBitsLeft;
1277 : }
1278 : }
1279 2236 : return skip;
1280 : }
1281 :
1282 : nsRect
1283 164 : nsIFrame::GetPaddingRectRelativeToSelf() const
1284 : {
1285 164 : nsMargin border(GetUsedBorder());
1286 164 : border.ApplySkipSides(GetSkipSides());
1287 164 : nsRect r(0, 0, mRect.width, mRect.height);
1288 164 : r.Deflate(border);
1289 164 : return r;
1290 : }
1291 :
1292 : nsRect
1293 80 : nsIFrame::GetPaddingRect() const
1294 : {
1295 80 : return GetPaddingRectRelativeToSelf() + GetPosition();
1296 : }
1297 :
1298 : WritingMode
1299 75 : nsIFrame::WritingModeForLine(WritingMode aSelfWM,
1300 : nsIFrame* aSubFrame) const
1301 : {
1302 75 : MOZ_ASSERT(aSelfWM == GetWritingMode());
1303 75 : WritingMode writingMode = aSelfWM;
1304 :
1305 75 : if (StyleTextReset()->mUnicodeBidi & NS_STYLE_UNICODE_BIDI_PLAINTEXT) {
1306 0 : nsBidiLevel frameLevel = nsBidiPresUtils::GetFrameBaseLevel(aSubFrame);
1307 0 : writingMode.SetDirectionFromBidiLevel(frameLevel);
1308 : }
1309 :
1310 75 : return writingMode;
1311 : }
1312 :
1313 : nsRect
1314 0 : nsIFrame::GetMarginRectRelativeToSelf() const
1315 : {
1316 0 : nsMargin m = GetUsedMargin();
1317 0 : m.ApplySkipSides(GetSkipSides());
1318 0 : nsRect r(0, 0, mRect.width, mRect.height);
1319 0 : r.Inflate(m);
1320 0 : return r;
1321 : }
1322 :
1323 : bool
1324 35077 : nsIFrame::IsTransformed(const nsStyleDisplay* aStyleDisplay,
1325 : EffectSet* aEffectSet) const
1326 : {
1327 35077 : MOZ_ASSERT(aStyleDisplay == StyleDisplay());
1328 37863 : return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
1329 2947 : (aStyleDisplay->HasTransform(this) ||
1330 1763 : IsSVGTransformed() ||
1331 35495 : HasAnimationOfTransform(aEffectSet)));
1332 : }
1333 :
1334 : bool
1335 657 : nsIFrame::HasAnimationOfTransform(EffectSet* aEffectSet) const
1336 : {
1337 : EffectSet* effects =
1338 657 : aEffectSet ? aEffectSet : EffectSet::GetEffectSet(this);
1339 :
1340 1270 : return mContent &&
1341 613 : nsLayoutUtils::HasAnimationOfProperty(effects, eCSSProperty_transform) &&
1342 657 : IsFrameOfType(eSupportsCSSTransforms) &&
1343 657 : mContent->GetPrimaryFrame() == this;
1344 : }
1345 :
1346 : bool
1347 1977 : nsIFrame::HasOpacityInternal(float aThreshold,
1348 : EffectSet* aEffectSet) const
1349 : {
1350 1977 : MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
1351 3585 : if (StyleEffects()->mOpacity < aThreshold ||
1352 1608 : (StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY)) {
1353 369 : return true;
1354 : }
1355 :
1356 : EffectSet* effects =
1357 1608 : aEffectSet ? aEffectSet : EffectSet::GetEffectSet(this);
1358 2848 : return (mContent && mContent->GetPrimaryFrame() == this &&
1359 2848 : nsLayoutUtils::HasAnimationOfProperty(effects, eCSSProperty_opacity));
1360 : }
1361 :
1362 : bool
1363 50 : nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
1364 : gfx::Matrix *aFromParentTransforms) const
1365 : {
1366 50 : return false;
1367 : }
1368 :
1369 : bool
1370 4731 : nsIFrame::Extend3DContext(const nsStyleDisplay* aStyleDisplay, mozilla::EffectSet* aEffectSet) const
1371 : {
1372 4731 : const nsStyleDisplay* disp = StyleDisplayWithOptionalParam(aStyleDisplay);
1373 4731 : if (disp->mTransformStyle != NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
1374 0 : !IsFrameOfType(nsIFrame::eSupportsCSSTransforms)) {
1375 4731 : return false;
1376 : }
1377 :
1378 : // If we're all scroll frame, then all descendants will be clipped, so we can't preserve 3d.
1379 0 : if (IsScrollFrame()) {
1380 0 : return false;
1381 : }
1382 :
1383 0 : if (HasOpacity(aEffectSet)) {
1384 0 : return false;
1385 : }
1386 :
1387 0 : const nsStyleEffects* effects = StyleEffects();
1388 0 : return !nsFrame::ShouldApplyOverflowClipping(this, disp) &&
1389 0 : !GetClipPropClipRect(disp, effects, GetSize()) &&
1390 0 : !nsSVGIntegrationUtils::UsingEffectsForFrame(this);
1391 : }
1392 :
1393 : bool
1394 5137 : nsIFrame::Combines3DTransformWithAncestors(const nsStyleDisplay* aStyleDisplay,
1395 : EffectSet* aEffectSet) const
1396 : {
1397 5137 : MOZ_ASSERT(aStyleDisplay == StyleDisplay());
1398 5137 : nsIFrame* parent = GetFlattenedTreeParentPrimaryFrame();
1399 5137 : if (!parent || !parent->Extend3DContext()) {
1400 5137 : return false;
1401 : }
1402 0 : return IsTransformed(aStyleDisplay,aEffectSet) ||
1403 0 : BackfaceIsHidden(aStyleDisplay);
1404 : }
1405 :
1406 : bool
1407 2017 : nsIFrame::In3DContextAndBackfaceIsHidden(EffectSet* aEffectSet) const
1408 : {
1409 : // While both tests fail most of the time, test BackfaceIsHidden()
1410 : // first since it's likely to fail faster.
1411 2017 : const nsStyleDisplay* disp = StyleDisplay();
1412 2017 : return BackfaceIsHidden(disp) &&
1413 2017 : Combines3DTransformWithAncestors(disp, aEffectSet);
1414 : }
1415 :
1416 : bool
1417 952 : nsIFrame::HasPerspective(const nsStyleDisplay* aStyleDisplay, EffectSet* aEffectSet) const
1418 : {
1419 952 : MOZ_ASSERT(aStyleDisplay == StyleDisplay());
1420 952 : if (!IsTransformed(aStyleDisplay, aEffectSet)) {
1421 804 : return false;
1422 : }
1423 148 : nsIFrame* containingBlock = GetContainingBlock(SKIP_SCROLLED_FRAME, aStyleDisplay);
1424 148 : if (!containingBlock) {
1425 0 : return false;
1426 : }
1427 148 : return containingBlock->ChildrenHavePerspective();
1428 : }
1429 :
1430 : nsRect
1431 291 : nsIFrame::GetContentRectRelativeToSelf() const
1432 : {
1433 291 : nsMargin bp(GetUsedBorderAndPadding());
1434 291 : bp.ApplySkipSides(GetSkipSides());
1435 291 : nsRect r(0, 0, mRect.width, mRect.height);
1436 291 : r.Deflate(bp);
1437 291 : return r;
1438 : }
1439 :
1440 : nsRect
1441 3 : nsIFrame::GetContentRect() const
1442 : {
1443 3 : return GetContentRectRelativeToSelf() + GetPosition();
1444 : }
1445 :
1446 : bool
1447 472 : nsIFrame::ComputeBorderRadii(const nsStyleCorners& aBorderRadius,
1448 : const nsSize& aFrameSize,
1449 : const nsSize& aBorderArea,
1450 : Sides aSkipSides,
1451 : nscoord aRadii[8])
1452 : {
1453 : // Percentages are relative to whichever side they're on.
1454 4248 : NS_FOR_CSS_HALF_CORNERS(i) {
1455 7552 : const nsStyleCoord c = aBorderRadius.Get(i);
1456 : nscoord axis =
1457 3776 : HalfCornerIsX(i) ? aFrameSize.width : aFrameSize.height;
1458 :
1459 3776 : if (c.IsCoordPercentCalcUnit()) {
1460 3776 : aRadii[i] = nsRuleNode::ComputeCoordPercentCalc(c, axis);
1461 3776 : if (aRadii[i] < 0) {
1462 : // clamp calc()
1463 0 : aRadii[i] = 0;
1464 : }
1465 : } else {
1466 0 : NS_NOTREACHED("ComputeBorderRadii: bad unit");
1467 0 : aRadii[i] = 0;
1468 : }
1469 : }
1470 :
1471 472 : if (aSkipSides.Top()) {
1472 0 : aRadii[eCornerTopLeftX] = 0;
1473 0 : aRadii[eCornerTopLeftY] = 0;
1474 0 : aRadii[eCornerTopRightX] = 0;
1475 0 : aRadii[eCornerTopRightY] = 0;
1476 : }
1477 :
1478 472 : if (aSkipSides.Right()) {
1479 0 : aRadii[eCornerTopRightX] = 0;
1480 0 : aRadii[eCornerTopRightY] = 0;
1481 0 : aRadii[eCornerBottomRightX] = 0;
1482 0 : aRadii[eCornerBottomRightY] = 0;
1483 : }
1484 :
1485 472 : if (aSkipSides.Bottom()) {
1486 0 : aRadii[eCornerBottomRightX] = 0;
1487 0 : aRadii[eCornerBottomRightY] = 0;
1488 0 : aRadii[eCornerBottomLeftX] = 0;
1489 0 : aRadii[eCornerBottomLeftY] = 0;
1490 : }
1491 :
1492 472 : if (aSkipSides.Left()) {
1493 0 : aRadii[eCornerBottomLeftX] = 0;
1494 0 : aRadii[eCornerBottomLeftY] = 0;
1495 0 : aRadii[eCornerTopLeftX] = 0;
1496 0 : aRadii[eCornerTopLeftY] = 0;
1497 : }
1498 :
1499 : // css3-background specifies this algorithm for reducing
1500 : // corner radii when they are too big.
1501 472 : bool haveRadius = false;
1502 472 : double ratio = 1.0f;
1503 2360 : NS_FOR_CSS_SIDES(side) {
1504 1888 : uint32_t hc1 = SideToHalfCorner(side, false, true);
1505 1888 : uint32_t hc2 = SideToHalfCorner(side, true, true);
1506 : nscoord length =
1507 1888 : SideIsVertical(side) ? aBorderArea.height : aBorderArea.width;
1508 1888 : nscoord sum = aRadii[hc1] + aRadii[hc2];
1509 1888 : if (sum)
1510 1492 : haveRadius = true;
1511 :
1512 : // avoid floating point division in the normal case
1513 1888 : if (length < sum)
1514 324 : ratio = std::min(ratio, double(length)/sum);
1515 : }
1516 472 : if (ratio < 1.0) {
1517 729 : NS_FOR_CSS_HALF_CORNERS(corner) {
1518 648 : aRadii[corner] *= ratio;
1519 : }
1520 : }
1521 :
1522 472 : return haveRadius;
1523 : }
1524 :
1525 : /* static */ void
1526 264 : nsIFrame::InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
1527 : {
1528 1320 : NS_FOR_CSS_SIDES(side) {
1529 1056 : nscoord offset = aOffsets.Side(side);
1530 1056 : uint32_t hc1 = SideToHalfCorner(side, false, false);
1531 1056 : uint32_t hc2 = SideToHalfCorner(side, true, false);
1532 1056 : aRadii[hc1] = std::max(0, aRadii[hc1] - offset);
1533 1056 : aRadii[hc2] = std::max(0, aRadii[hc2] - offset);
1534 : }
1535 264 : }
1536 :
1537 : /* static */ void
1538 0 : nsIFrame::OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
1539 : {
1540 0 : auto AdjustOffset = [] (const uint32_t aRadius, const nscoord aOffset) {
1541 : // Implement the cubic formula to adjust offset when aOffset > 0 and
1542 : // aRadius / aOffset < 1.
1543 : // https://drafts.csswg.org/css-shapes/#valdef-shape-box-margin-box
1544 0 : if (aOffset > 0) {
1545 0 : const double ratio = aRadius / double(aOffset);
1546 0 : if (ratio < 1.0) {
1547 0 : return nscoord(aOffset * (1.0 + std::pow(ratio - 1, 3)));
1548 : }
1549 : }
1550 0 : return aOffset;
1551 : };
1552 :
1553 0 : NS_FOR_CSS_SIDES(side) {
1554 0 : const nscoord offset = aOffsets.Side(side);
1555 0 : const uint32_t hc1 = SideToHalfCorner(side, false, false);
1556 0 : const uint32_t hc2 = SideToHalfCorner(side, true, false);
1557 0 : if (aRadii[hc1] > 0) {
1558 0 : const nscoord offset1 = AdjustOffset(aRadii[hc1], offset);
1559 0 : aRadii[hc1] = std::max(0, aRadii[hc1] + offset1);
1560 : }
1561 0 : if (aRadii[hc2] > 0) {
1562 0 : const nscoord offset2 = AdjustOffset(aRadii[hc2], offset);
1563 0 : aRadii[hc2] = std::max(0, aRadii[hc2] + offset2);
1564 : }
1565 : }
1566 0 : }
1567 :
1568 : /* virtual */ bool
1569 1391 : nsIFrame::GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
1570 : Sides aSkipSides, nscoord aRadii[8]) const
1571 : {
1572 1391 : if (!mMayHaveRoundedCorners) {
1573 853 : memset(aRadii, 0, sizeof(nscoord) * 8);
1574 853 : return false;
1575 : }
1576 :
1577 538 : if (IsThemed()) {
1578 : // When we're themed, the native theme code draws the border and
1579 : // background, and therefore it doesn't make sense to tell other
1580 : // code that's interested in border-radius that we have any radii.
1581 : //
1582 : // In an ideal world, we might have a way for the them to tell us an
1583 : // border radius, but since we don't, we're better off assuming
1584 : // zero.
1585 594 : NS_FOR_CSS_HALF_CORNERS(corner) {
1586 528 : aRadii[corner] = 0;
1587 : }
1588 66 : return false;
1589 : }
1590 :
1591 472 : const_cast<nsIFrame*>(this)->mMayHaveRoundedCorners =
1592 472 : ComputeBorderRadii(StyleBorder()->mBorderRadius,
1593 : aFrameSize, aBorderArea,
1594 : aSkipSides, aRadii);
1595 472 : return mMayHaveRoundedCorners;
1596 : }
1597 :
1598 : bool
1599 971 : nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
1600 : {
1601 971 : nsSize sz = GetSize();
1602 971 : return GetBorderRadii(sz, sz, GetSkipSides(), aRadii);
1603 : }
1604 :
1605 : bool
1606 0 : nsIFrame::GetMarginBoxBorderRadii(nscoord aRadii[8]) const
1607 : {
1608 0 : if (!GetBorderRadii(aRadii)) {
1609 0 : return false;
1610 : }
1611 0 : OutsetBorderRadii(aRadii, GetUsedMargin());
1612 0 : NS_FOR_CSS_HALF_CORNERS(corner) {
1613 0 : if (aRadii[corner]) {
1614 0 : return true;
1615 : }
1616 : }
1617 0 : return false;
1618 : }
1619 :
1620 : bool
1621 290 : nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const
1622 : {
1623 290 : if (!GetBorderRadii(aRadii))
1624 266 : return false;
1625 24 : InsetBorderRadii(aRadii, GetUsedBorder());
1626 24 : NS_FOR_CSS_HALF_CORNERS(corner) {
1627 24 : if (aRadii[corner])
1628 24 : return true;
1629 : }
1630 0 : return false;
1631 : }
1632 :
1633 : bool
1634 359 : nsIFrame::GetContentBoxBorderRadii(nscoord aRadii[8]) const
1635 : {
1636 359 : if (!GetBorderRadii(aRadii))
1637 191 : return false;
1638 168 : InsetBorderRadii(aRadii, GetUsedBorderAndPadding());
1639 1320 : NS_FOR_CSS_HALF_CORNERS(corner) {
1640 1176 : if (aRadii[corner])
1641 24 : return true;
1642 : }
1643 144 : return false;
1644 : }
1645 :
1646 : bool
1647 0 : nsIFrame::GetShapeBoxBorderRadii(nscoord aRadii[8]) const
1648 : {
1649 0 : switch (StyleDisplay()->mShapeOutside.GetReferenceBox()) {
1650 : case StyleGeometryBox::NoBox:
1651 0 : return false;
1652 : case StyleGeometryBox::ContentBox:
1653 0 : return GetContentBoxBorderRadii(aRadii);
1654 : case StyleGeometryBox::PaddingBox:
1655 0 : return GetPaddingBoxBorderRadii(aRadii);
1656 : case StyleGeometryBox::BorderBox:
1657 0 : return GetBorderRadii(aRadii);
1658 : case StyleGeometryBox::MarginBox:
1659 0 : return GetMarginBoxBorderRadii(aRadii);
1660 : default:
1661 0 : MOZ_ASSERT_UNREACHABLE("Unexpected box value");
1662 : return false;
1663 : }
1664 : return false;
1665 : }
1666 :
1667 : nsStyleContext*
1668 2818 : nsFrame::GetAdditionalStyleContext(int32_t aIndex) const
1669 : {
1670 2818 : NS_PRECONDITION(aIndex >= 0, "invalid index number");
1671 2818 : return nullptr;
1672 : }
1673 :
1674 : void
1675 0 : nsFrame::SetAdditionalStyleContext(int32_t aIndex,
1676 : nsStyleContext* aStyleContext)
1677 : {
1678 0 : NS_PRECONDITION(aIndex >= 0, "invalid index number");
1679 0 : }
1680 :
1681 : nscoord
1682 112 : nsFrame::GetLogicalBaseline(WritingMode aWritingMode) const
1683 : {
1684 112 : NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
1685 : "frame must not be dirty");
1686 : // Baseline for inverted line content is the top (block-start) margin edge,
1687 : // as the frame is in effect "flipped" for alignment purposes.
1688 112 : if (aWritingMode.IsLineInverted()) {
1689 0 : return -GetLogicalUsedMargin(aWritingMode).BStart(aWritingMode);
1690 : }
1691 : // Otherwise, the bottom margin edge, per CSS2.1's definition of the
1692 : // 'baseline' value of 'vertical-align'.
1693 112 : return BSize(aWritingMode) +
1694 112 : GetLogicalUsedMargin(aWritingMode).BEnd(aWritingMode);
1695 : }
1696 :
1697 : const nsFrameList&
1698 180 : nsFrame::GetChildList(ChildListID aListID) const
1699 : {
1700 206 : if (IsAbsoluteContainer() &&
1701 26 : aListID == GetAbsoluteListID()) {
1702 26 : return GetAbsoluteContainingBlock()->GetChildList();
1703 : } else {
1704 154 : return nsFrameList::EmptyList();
1705 : }
1706 : }
1707 :
1708 : void
1709 6008 : nsFrame::GetChildLists(nsTArray<ChildList>* aLists) const
1710 : {
1711 6008 : if (IsAbsoluteContainer()) {
1712 585 : nsFrameList absoluteList = GetAbsoluteContainingBlock()->GetChildList();
1713 585 : absoluteList.AppendIfNonempty(aLists, GetAbsoluteListID());
1714 : }
1715 6008 : }
1716 :
1717 : void
1718 1326 : nsIFrame::GetCrossDocChildLists(nsTArray<ChildList>* aLists)
1719 : {
1720 1326 : nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(this);
1721 1326 : if (subdocumentFrame) {
1722 : // Descend into the subdocument
1723 2 : nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame();
1724 2 : if (root) {
1725 0 : aLists->AppendElement(nsIFrame::ChildList(
1726 0 : nsFrameList(root, nsLayoutUtils::GetLastSibling(root)),
1727 0 : nsIFrame::kPrincipalList));
1728 : }
1729 : }
1730 :
1731 1326 : GetChildLists(aLists);
1732 1326 : }
1733 :
1734 : Visibility
1735 126 : nsIFrame::GetVisibility() const
1736 : {
1737 126 : if (!(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED)) {
1738 126 : return Visibility::UNTRACKED;
1739 : }
1740 :
1741 0 : bool isSet = false;
1742 0 : uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
1743 :
1744 0 : MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
1745 : "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
1746 :
1747 : return visibleCount > 0
1748 0 : ? Visibility::APPROXIMATELY_VISIBLE
1749 0 : : Visibility::APPROXIMATELY_NONVISIBLE;
1750 : }
1751 :
1752 : void
1753 0 : nsIFrame::UpdateVisibilitySynchronously()
1754 : {
1755 0 : nsIPresShell* presShell = PresContext()->PresShell();
1756 0 : if (!presShell) {
1757 0 : return;
1758 : }
1759 :
1760 0 : if (presShell->AssumeAllFramesVisible()) {
1761 0 : presShell->EnsureFrameInApproximatelyVisibleList(this);
1762 0 : return;
1763 : }
1764 :
1765 0 : bool visible = StyleVisibility()->IsVisible();
1766 0 : nsIFrame* f = GetParent();
1767 0 : nsRect rect = GetRectRelativeToSelf();
1768 0 : nsIFrame* rectFrame = this;
1769 0 : while (f && visible) {
1770 0 : nsIScrollableFrame* sf = do_QueryFrame(f);
1771 0 : if (sf) {
1772 : nsRect transformedRect =
1773 0 : nsLayoutUtils::TransformFrameRectToAncestor(rectFrame, rect, f);
1774 0 : if (!sf->IsRectNearlyVisible(transformedRect)) {
1775 0 : visible = false;
1776 0 : break;
1777 : }
1778 :
1779 : // In this code we're trying to synchronously update *approximate*
1780 : // visibility. (In the future we may update precise visibility here as
1781 : // well, which is why the method name does not contain 'approximate'.) The
1782 : // IsRectNearlyVisible() check above tells us that the rect we're checking
1783 : // is approximately visible within the scrollframe, but we still need to
1784 : // ensure that, even if it was scrolled into view, it'd be visible when we
1785 : // consider the rest of the document. To do that, we move transformedRect
1786 : // to be contained in the scrollport as best we can (it might not fit) to
1787 : // pretend that it was scrolled into view.
1788 0 : rect = transformedRect.MoveInsideAndClamp(sf->GetScrollPortRect());
1789 0 : rectFrame = f;
1790 : }
1791 0 : nsIFrame* parent = f->GetParent();
1792 0 : if (!parent) {
1793 0 : parent = nsLayoutUtils::GetCrossDocParentFrame(f);
1794 0 : if (parent && parent->PresContext()->IsChrome()) {
1795 0 : break;
1796 : }
1797 : }
1798 0 : f = parent;
1799 : }
1800 :
1801 0 : if (visible) {
1802 0 : presShell->EnsureFrameInApproximatelyVisibleList(this);
1803 : } else {
1804 0 : presShell->RemoveFrameFromApproximatelyVisibleList(this);
1805 : }
1806 : }
1807 :
1808 : void
1809 0 : nsIFrame::EnableVisibilityTracking()
1810 : {
1811 0 : if (GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED) {
1812 0 : return; // Nothing to do.
1813 : }
1814 :
1815 0 : MOZ_ASSERT(!HasProperty(VisibilityStateProperty()),
1816 : "Shouldn't have a VisibilityStateProperty value "
1817 : "if NS_FRAME_VISIBILITY_IS_TRACKED is not set");
1818 :
1819 : // Add the state bit so we know to track visibility for this frame, and
1820 : // initialize the frame property.
1821 0 : AddStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
1822 0 : SetProperty(VisibilityStateProperty(), 0);
1823 :
1824 0 : nsIPresShell* presShell = PresContext()->PresShell();
1825 0 : if (!presShell) {
1826 0 : return;
1827 : }
1828 :
1829 : // Schedule a visibility update. This method will virtually always be called
1830 : // when layout has changed anyway, so it's very unlikely that any additional
1831 : // visibility updates will be triggered by this, but this way we guarantee
1832 : // that if this frame is currently visible we'll eventually find out.
1833 0 : presShell->ScheduleApproximateFrameVisibilityUpdateSoon();
1834 : }
1835 :
1836 : void
1837 126 : nsIFrame::DisableVisibilityTracking()
1838 : {
1839 126 : if (!(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED)) {
1840 252 : return; // Nothing to do.
1841 : }
1842 :
1843 0 : bool isSet = false;
1844 0 : uint32_t visibleCount = RemoveProperty(VisibilityStateProperty(), &isSet);
1845 :
1846 0 : MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
1847 : "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
1848 :
1849 0 : RemoveStateBits(NS_FRAME_VISIBILITY_IS_TRACKED);
1850 :
1851 0 : if (visibleCount == 0) {
1852 0 : return; // We were nonvisible.
1853 : }
1854 :
1855 : // We were visible, so send an OnVisibilityChange() notification.
1856 0 : OnVisibilityChange(Visibility::APPROXIMATELY_NONVISIBLE);
1857 : }
1858 :
1859 : void
1860 0 : nsIFrame::DecApproximateVisibleCount(const Maybe<OnNonvisible>& aNonvisibleAction
1861 : /* = Nothing() */)
1862 : {
1863 0 : MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
1864 :
1865 0 : bool isSet = false;
1866 0 : uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
1867 :
1868 0 : MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
1869 : "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
1870 0 : MOZ_ASSERT(visibleCount > 0, "Frame is already nonvisible and we're "
1871 : "decrementing its visible count?");
1872 :
1873 0 : visibleCount--;
1874 0 : SetProperty(VisibilityStateProperty(), visibleCount);
1875 0 : if (visibleCount > 0) {
1876 0 : return;
1877 : }
1878 :
1879 : // We just became nonvisible, so send an OnVisibilityChange() notification.
1880 0 : OnVisibilityChange(Visibility::APPROXIMATELY_NONVISIBLE, aNonvisibleAction);
1881 : }
1882 :
1883 : void
1884 0 : nsIFrame::IncApproximateVisibleCount()
1885 : {
1886 0 : MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED);
1887 :
1888 0 : bool isSet = false;
1889 0 : uint32_t visibleCount = GetProperty(VisibilityStateProperty(), &isSet);
1890 :
1891 0 : MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value "
1892 : "if NS_FRAME_VISIBILITY_IS_TRACKED is set");
1893 :
1894 0 : visibleCount++;
1895 0 : SetProperty(VisibilityStateProperty(), visibleCount);
1896 0 : if (visibleCount > 1) {
1897 0 : return;
1898 : }
1899 :
1900 : // We just became visible, so send an OnVisibilityChange() notification.
1901 0 : OnVisibilityChange(Visibility::APPROXIMATELY_VISIBLE);
1902 : }
1903 :
1904 : void
1905 0 : nsIFrame::OnVisibilityChange(Visibility aNewVisibility,
1906 : const Maybe<OnNonvisible>& aNonvisibleAction
1907 : /* = Nothing() */)
1908 : {
1909 : // XXX(seth): In bug 1218990 we'll implement visibility tracking for CSS
1910 : // images here.
1911 0 : }
1912 :
1913 : static nsIFrame*
1914 0 : GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame)
1915 : {
1916 0 : nsIContent* capturingContent = nsIPresShell::GetCapturingContent();
1917 0 : if (capturingContent) {
1918 0 : nsIFrame* activeFrame = aPresContext->GetPrimaryFrameFor(capturingContent);
1919 0 : return activeFrame ? activeFrame : aFrame;
1920 : }
1921 :
1922 0 : return aFrame;
1923 : }
1924 :
1925 : int16_t
1926 0 : nsFrame::DisplaySelection(nsPresContext* aPresContext, bool isOkToTurnOn)
1927 : {
1928 0 : int16_t selType = nsISelectionController::SELECTION_OFF;
1929 :
1930 0 : nsCOMPtr<nsISelectionController> selCon;
1931 0 : nsresult result = GetSelectionController(aPresContext, getter_AddRefs(selCon));
1932 0 : if (NS_SUCCEEDED(result) && selCon) {
1933 0 : result = selCon->GetDisplaySelection(&selType);
1934 0 : if (NS_SUCCEEDED(result) && (selType != nsISelectionController::SELECTION_OFF)) {
1935 : // Check whether style allows selection.
1936 0 : if (!IsSelectable(nullptr)) {
1937 0 : selType = nsISelectionController::SELECTION_OFF;
1938 0 : isOkToTurnOn = false;
1939 : }
1940 : }
1941 0 : if (isOkToTurnOn && (selType == nsISelectionController::SELECTION_OFF)) {
1942 0 : selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON);
1943 0 : selType = nsISelectionController::SELECTION_ON;
1944 : }
1945 : }
1946 0 : return selType;
1947 : }
1948 :
1949 : class nsDisplaySelectionOverlay : public nsDisplayItem {
1950 : public:
1951 0 : nsDisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
1952 : nsFrame* aFrame, int16_t aSelectionValue)
1953 0 : : nsDisplayItem(aBuilder, aFrame), mSelectionValue(aSelectionValue) {
1954 0 : MOZ_COUNT_CTOR(nsDisplaySelectionOverlay);
1955 0 : }
1956 : #ifdef NS_BUILD_REFCNT_LOGGING
1957 0 : virtual ~nsDisplaySelectionOverlay() {
1958 0 : MOZ_COUNT_DTOR(nsDisplaySelectionOverlay);
1959 0 : }
1960 : #endif
1961 :
1962 : virtual void Paint(nsDisplayListBuilder* aBuilder,
1963 : gfxContext* aCtx) override;
1964 0 : NS_DISPLAY_DECL_NAME("SelectionOverlay", TYPE_SELECTION_OVERLAY)
1965 : private:
1966 : int16_t mSelectionValue;
1967 : };
1968 :
1969 0 : void nsDisplaySelectionOverlay::Paint(nsDisplayListBuilder* aBuilder,
1970 : gfxContext* aCtx)
1971 : {
1972 0 : DrawTarget& aDrawTarget = *aCtx->GetDrawTarget();
1973 :
1974 : LookAndFeel::ColorID colorID;
1975 0 : if (mSelectionValue == nsISelectionController::SELECTION_ON) {
1976 0 : colorID = LookAndFeel::eColorID_TextSelectBackground;
1977 0 : } else if (mSelectionValue == nsISelectionController::SELECTION_ATTENTION) {
1978 0 : colorID = LookAndFeel::eColorID_TextSelectBackgroundAttention;
1979 : } else {
1980 0 : colorID = LookAndFeel::eColorID_TextSelectBackgroundDisabled;
1981 : }
1982 :
1983 0 : Color c = Color::FromABGR(LookAndFeel::GetColor(colorID, NS_RGB(255, 255, 255)));
1984 0 : c.a = .5;
1985 0 : ColorPattern color(ToDeviceColor(c));
1986 :
1987 : nsIntRect pxRect =
1988 0 : mVisibleRect.ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
1989 0 : Rect rect(pxRect.x, pxRect.y, pxRect.width, pxRect.height);
1990 0 : MaybeSnapToDevicePixels(rect, aDrawTarget, true);
1991 :
1992 0 : aDrawTarget.FillRect(rect, color);
1993 0 : }
1994 :
1995 : /********************************************************
1996 : * Refreshes each content's frame
1997 : *********************************************************/
1998 :
1999 : void
2000 1916 : nsFrame::DisplaySelectionOverlay(nsDisplayListBuilder* aBuilder,
2001 : nsDisplayList* aList,
2002 : uint16_t aContentType)
2003 : {
2004 1916 : if (!IsSelected() || !IsVisibleForPainting(aBuilder))
2005 3832 : return;
2006 :
2007 0 : nsPresContext* presContext = PresContext();
2008 0 : nsIPresShell *shell = presContext->PresShell();
2009 0 : if (!shell)
2010 0 : return;
2011 :
2012 0 : int16_t displaySelection = shell->GetSelectionFlags();
2013 0 : if (!(displaySelection & aContentType))
2014 0 : return;
2015 :
2016 0 : const nsFrameSelection* frameSelection = GetConstFrameSelection();
2017 0 : int16_t selectionValue = frameSelection->GetDisplaySelection();
2018 :
2019 0 : if (selectionValue <= nsISelectionController::SELECTION_HIDDEN)
2020 0 : return; // selection is hidden or off
2021 :
2022 0 : nsIContent *newContent = mContent->GetParent();
2023 :
2024 : //check to see if we are anonymous content
2025 0 : int32_t offset = 0;
2026 0 : if (newContent) {
2027 : // XXXbz there has GOT to be a better way of determining this!
2028 0 : offset = newContent->IndexOf(mContent);
2029 : }
2030 :
2031 : //look up to see what selection(s) are on this frame
2032 : UniquePtr<SelectionDetails> details
2033 0 : = frameSelection->LookUpSelection(newContent, offset, 1, false);
2034 0 : if (!details)
2035 0 : return;
2036 :
2037 0 : bool normal = false;
2038 0 : for (SelectionDetails* sd = details.get(); sd; sd = sd->mNext.get()) {
2039 0 : if (sd->mSelectionType == SelectionType::eNormal) {
2040 0 : normal = true;
2041 : }
2042 : }
2043 :
2044 0 : if (!normal && aContentType == nsISelectionDisplay::DISPLAY_IMAGES) {
2045 : // Don't overlay an image if it's not in the primary selection.
2046 0 : return;
2047 : }
2048 :
2049 : aList->AppendNewToTop(new (aBuilder)
2050 0 : nsDisplaySelectionOverlay(aBuilder, this, selectionValue));
2051 : }
2052 :
2053 : void
2054 2828 : nsFrame::DisplayOutlineUnconditional(nsDisplayListBuilder* aBuilder,
2055 : const nsDisplayListSet& aLists)
2056 : {
2057 2828 : if (!StyleOutline()->ShouldPaintOutline()) {
2058 2828 : return;
2059 : }
2060 :
2061 0 : aLists.Outlines()->AppendNewToTop(
2062 0 : new (aBuilder) nsDisplayOutline(aBuilder, this));
2063 : }
2064 :
2065 : void
2066 79 : nsFrame::DisplayOutline(nsDisplayListBuilder* aBuilder,
2067 : const nsDisplayListSet& aLists)
2068 : {
2069 79 : if (!IsVisibleForPainting(aBuilder))
2070 0 : return;
2071 :
2072 79 : DisplayOutlineUnconditional(aBuilder, aLists);
2073 : }
2074 :
2075 : void
2076 0 : nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
2077 : const nsRect& aDirtyRect, nsDisplayList* aList)
2078 : {
2079 0 : if (!IsVisibleForPainting(aBuilder))
2080 0 : return;
2081 :
2082 0 : aList->AppendNewToTop(new (aBuilder) nsDisplayCaret(aBuilder, this));
2083 : }
2084 :
2085 : nscolor
2086 0 : nsIFrame::GetCaretColorAt(int32_t aOffset)
2087 : {
2088 0 : return nsLayoutUtils::GetColor(this, &nsStyleUserInterface::mCaretColor);
2089 : }
2090 :
2091 : bool
2092 2749 : nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
2093 : const nsDisplayListSet& aLists,
2094 : bool aForceBackground)
2095 : {
2096 : // Here we don't try to detect background propagation. Frames that might
2097 : // receive a propagated background should just set aForceBackground to
2098 : // true.
2099 10702 : if (aBuilder->IsForEventDelivery() || aForceBackground ||
2100 7628 : !StyleBackground()->IsTransparent(this) || StyleDisplay()->mAppearance) {
2101 1524 : return nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
2102 1016 : aBuilder, this, GetRectRelativeToSelf(), aLists.BorderBackground());
2103 : }
2104 2241 : return false;
2105 : }
2106 :
2107 : void
2108 2872 : nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
2109 : const nsDisplayListSet& aLists,
2110 : bool aForceBackground)
2111 : {
2112 : // The visibility check belongs here since child elements have the
2113 : // opportunity to override the visibility property and display even if
2114 : // their parent is hidden.
2115 2872 : if (!IsVisibleForPainting(aBuilder)) {
2116 123 : return;
2117 : }
2118 :
2119 2749 : nsCSSShadowArray* shadows = StyleEffects()->mBoxShadow;
2120 2749 : if (shadows && shadows->HasShadowWithInset(false)) {
2121 48 : aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
2122 96 : nsDisplayBoxShadowOuter(aBuilder, this));
2123 : }
2124 :
2125 2749 : bool bgIsThemed = DisplayBackgroundUnconditional(aBuilder, aLists,
2126 2749 : aForceBackground);
2127 :
2128 2749 : if (shadows && shadows->HasShadowWithInset(true)) {
2129 24 : aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
2130 48 : nsDisplayBoxShadowInner(aBuilder, this));
2131 : }
2132 :
2133 : // If there's a themed background, we should not create a border item.
2134 : // It won't be rendered.
2135 2749 : if (!bgIsThemed && StyleBorder()->HasBorder()) {
2136 179 : aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
2137 358 : nsDisplayBorder(aBuilder, this));
2138 : }
2139 :
2140 2749 : DisplayOutlineUnconditional(aBuilder, aLists);
2141 : }
2142 :
2143 0 : inline static bool IsSVGContentWithCSSClip(const nsIFrame *aFrame)
2144 : {
2145 : // The CSS spec says that the 'clip' property only applies to absolutely
2146 : // positioned elements, whereas the SVG spec says that it applies to SVG
2147 : // elements regardless of the value of the 'position' property. Here we obey
2148 : // the CSS spec for outer-<svg> (since that's what we generally do), but
2149 : // obey the SVG spec for other SVG elements to which 'clip' applies.
2150 0 : return (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
2151 0 : aFrame->GetContent()->IsAnyOfSVGElements(nsGkAtoms::svg,
2152 0 : nsGkAtoms::foreignObject);
2153 : }
2154 :
2155 : Maybe<nsRect>
2156 3104 : nsIFrame::GetClipPropClipRect(const nsStyleDisplay* aDisp,
2157 : const nsStyleEffects* aEffects,
2158 : const nsSize& aSize) const
2159 : {
2160 6208 : if (!(aEffects->mClipFlags & NS_STYLE_CLIP_RECT) ||
2161 0 : !(aDisp->IsAbsolutelyPositioned(this) || IsSVGContentWithCSSClip(this))) {
2162 3104 : return Nothing();
2163 : }
2164 :
2165 0 : nsRect rect = aEffects->mClip;
2166 0 : if (MOZ_LIKELY(StyleBorder()->mBoxDecorationBreak ==
2167 : StyleBoxDecorationBreak::Slice)) {
2168 : // The clip applies to the joined boxes so it's relative the first
2169 : // continuation.
2170 0 : nscoord y = 0;
2171 0 : for (nsIFrame* f = GetPrevContinuation(); f; f = f->GetPrevContinuation()) {
2172 0 : y += f->GetRect().height;
2173 : }
2174 0 : rect.MoveBy(nsPoint(0, -y));
2175 : }
2176 :
2177 0 : if (NS_STYLE_CLIP_RIGHT_AUTO & aEffects->mClipFlags) {
2178 0 : rect.width = aSize.width - rect.x;
2179 : }
2180 0 : if (NS_STYLE_CLIP_BOTTOM_AUTO & aEffects->mClipFlags) {
2181 0 : rect.height = aSize.height - rect.y;
2182 : }
2183 0 : return Some(rect);
2184 : }
2185 :
2186 : /**
2187 : * If the CSS 'overflow' property applies to this frame, and is not
2188 : * handled by constructing a dedicated nsHTML/XULScrollFrame, set up clipping
2189 : * for that overflow in aBuilder->ClipState() to clip all containing-block
2190 : * descendants.
2191 : *
2192 : * Return true if clipping was applied.
2193 : */
2194 : static bool
2195 1364 : ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
2196 : const nsIFrame* aFrame,
2197 : const nsStyleDisplay* aDisp,
2198 : DisplayListClipState::AutoClipMultiple& aClipState)
2199 : {
2200 : // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
2201 : // frames, and any non-visible value for blocks in a paginated context).
2202 : // We allow -moz-hidden-unscrollable to apply to any kind of frame. This
2203 : // is required by comboboxes which make their display text (an inline frame)
2204 : // have clipping.
2205 1364 : if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) {
2206 1305 : return false;
2207 : }
2208 118 : nsRect clipRect;
2209 59 : bool haveRadii = false;
2210 : nscoord radii[8];
2211 59 : if (aFrame->StyleDisplay()->mOverflowClipBox ==
2212 : NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
2213 59 : clipRect = aFrame->GetPaddingRectRelativeToSelf() +
2214 118 : aBuilder->ToReferenceFrame(aFrame);
2215 59 : haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
2216 : } else {
2217 0 : clipRect = aFrame->GetContentRectRelativeToSelf() +
2218 0 : aBuilder->ToReferenceFrame(aFrame);
2219 : // XXX border-radius
2220 : }
2221 59 : aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr);
2222 59 : return true;
2223 : }
2224 :
2225 : #ifdef DEBUG
2226 0 : static void PaintDebugBorder(nsIFrame* aFrame, DrawTarget* aDrawTarget,
2227 : const nsRect& aDirtyRect, nsPoint aPt)
2228 : {
2229 0 : nsRect r(aPt, aFrame->GetSize());
2230 0 : int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
2231 0 : Color blueOrRed(aFrame->HasView() ? Color(0.f, 0.f, 1.f, 1.f) :
2232 0 : Color(1.f, 0.f, 0.f, 1.f));
2233 0 : aDrawTarget->StrokeRect(NSRectToRect(r, appUnitsPerDevPixel),
2234 0 : ColorPattern(ToDeviceColor(blueOrRed)));
2235 0 : }
2236 :
2237 0 : static void PaintEventTargetBorder(nsIFrame* aFrame, DrawTarget* aDrawTarget,
2238 : const nsRect& aDirtyRect, nsPoint aPt)
2239 : {
2240 0 : nsRect r(aPt, aFrame->GetSize());
2241 0 : int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
2242 0 : ColorPattern purple(ToDeviceColor(Color(.5f, 0.f, .5f, 1.f)));
2243 0 : aDrawTarget->StrokeRect(NSRectToRect(r, appUnitsPerDevPixel), purple);
2244 0 : }
2245 :
2246 : static void
2247 3113 : DisplayDebugBorders(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
2248 : const nsDisplayListSet& aLists) {
2249 : // Draw a border around the child
2250 : // REVIEW: From nsContainerFrame::PaintChild
2251 3113 : if (nsFrame::GetShowFrameBorders() && !aFrame->GetRect().IsEmpty()) {
2252 0 : aLists.Outlines()->AppendNewToTop(new (aBuilder)
2253 : nsDisplayGeneric(aBuilder, aFrame, PaintDebugBorder, "DebugBorder",
2254 0 : nsDisplayItem::TYPE_DEBUG_BORDER));
2255 : }
2256 : // Draw a border around the current event target
2257 3113 : if (nsFrame::GetShowEventTargetFrameBorder() &&
2258 0 : aFrame->PresContext()->PresShell()->GetDrawEventTargetFrame() == aFrame) {
2259 0 : aLists.Outlines()->AppendNewToTop(new (aBuilder)
2260 : nsDisplayGeneric(aBuilder, aFrame, PaintEventTargetBorder, "EventTargetBorder",
2261 0 : nsDisplayItem::TYPE_EVENT_TARGET_BORDER));
2262 : }
2263 3113 : }
2264 : #endif
2265 :
2266 : static bool
2267 0 : IsScrollFrameActive(nsDisplayListBuilder* aBuilder, nsIScrollableFrame* aScrollableFrame)
2268 : {
2269 0 : return aScrollableFrame && aScrollableFrame->IsScrollingActive(aBuilder);
2270 : }
2271 :
2272 : /**
2273 : * Returns whether a display item that gets created with the builder's current
2274 : * state will have a scrolled clip, i.e. a clip that is scrolled by a scroll
2275 : * frame which does not move the item itself.
2276 : */
2277 : static bool
2278 83 : BuilderHasScrolledClip(nsDisplayListBuilder* aBuilder)
2279 : {
2280 : const DisplayItemClipChain* currentClip =
2281 83 : aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder);
2282 83 : if (!currentClip) {
2283 83 : return false;
2284 : }
2285 :
2286 0 : const ActiveScrolledRoot* currentClipASR = currentClip->mASR;
2287 0 : const ActiveScrolledRoot* currentASR = aBuilder->CurrentActiveScrolledRoot();
2288 0 : return ActiveScrolledRoot::PickDescendant(currentClipASR, currentASR) != currentASR;
2289 : }
2290 :
2291 : class AutoSaveRestoreContainsBlendMode
2292 : {
2293 : nsDisplayListBuilder& mBuilder;
2294 : bool mSavedContainsBlendMode;
2295 : public:
2296 613 : explicit AutoSaveRestoreContainsBlendMode(nsDisplayListBuilder& aBuilder)
2297 613 : : mBuilder(aBuilder)
2298 613 : , mSavedContainsBlendMode(aBuilder.ContainsBlendMode())
2299 613 : { }
2300 :
2301 1226 : ~AutoSaveRestoreContainsBlendMode() {
2302 613 : mBuilder.SetContainsBlendMode(mSavedContainsBlendMode);
2303 613 : }
2304 : };
2305 :
2306 : static void
2307 3696 : CheckForApzAwareEventHandlers(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
2308 : {
2309 3696 : nsIContent* content = aFrame->GetContent();
2310 3696 : if (!content) {
2311 53 : return;
2312 : }
2313 :
2314 3643 : if (content->IsNodeApzAware()) {
2315 72 : aBuilder->SetAncestorHasApzAwareEventHandler(true);
2316 : }
2317 : }
2318 :
2319 : /**
2320 : * True if aDescendant participates the context aAncestor participating.
2321 : */
2322 : static bool
2323 0 : FrameParticipatesIn3DContext(nsIFrame* aAncestor, nsIFrame* aDescendant) {
2324 0 : MOZ_ASSERT(aAncestor != aDescendant);
2325 0 : MOZ_ASSERT(aAncestor->Extend3DContext());
2326 : nsIFrame* frame;
2327 0 : for (frame = aDescendant->GetFlattenedTreeParentPrimaryFrame();
2328 0 : frame && aAncestor != frame;
2329 : frame = frame->GetFlattenedTreeParentPrimaryFrame()) {
2330 0 : if (!frame->Extend3DContext()) {
2331 0 : return false;
2332 : }
2333 : }
2334 0 : MOZ_ASSERT(frame == aAncestor);
2335 0 : return true;
2336 : }
2337 :
2338 : static bool
2339 0 : ItemParticipatesIn3DContext(nsIFrame* aAncestor, nsDisplayItem* aItem)
2340 : {
2341 : nsIFrame* transformFrame;
2342 0 : if (aItem->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
2343 0 : transformFrame = aItem->Frame();
2344 0 : } else if (aItem->GetType() == nsDisplayItem::TYPE_PERSPECTIVE) {
2345 0 : transformFrame = static_cast<nsDisplayPerspective*>(aItem)->TransformFrame();
2346 : } else {
2347 0 : return false;
2348 : }
2349 0 : if (aAncestor == transformFrame) {
2350 0 : return true;
2351 : }
2352 0 : return FrameParticipatesIn3DContext(aAncestor, transformFrame);
2353 : }
2354 :
2355 : static void
2356 0 : WrapSeparatorTransform(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
2357 : nsRect& aDirtyRect,
2358 : nsDisplayList* aSource, nsDisplayList* aTarget,
2359 : int aIndex) {
2360 0 : if (!aSource->IsEmpty()) {
2361 : nsDisplayTransform *sepIdItem =
2362 : new (aBuilder) nsDisplayTransform(aBuilder, aFrame, aSource,
2363 0 : aDirtyRect, Matrix4x4(), aIndex);
2364 0 : sepIdItem->SetNoExtendContext();
2365 0 : aTarget->AppendToTop(sepIdItem);
2366 : }
2367 0 : }
2368 :
2369 : void
2370 636 : nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
2371 : const nsRect& aDirtyRect,
2372 : nsDisplayList* aList) {
2373 636 : if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
2374 23 : return;
2375 :
2376 : // Replaced elements have their visibility handled here, because
2377 : // they're visually atomic
2378 636 : if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
2379 21 : return;
2380 :
2381 615 : const nsStyleDisplay* disp = StyleDisplay();
2382 615 : const nsStyleEffects* effects = StyleEffects();
2383 615 : EffectSet* effectSet = EffectSet::GetEffectSet(this);
2384 : // We can stop right away if this is a zero-opacity stacking context and
2385 : // we're painting, and we're not animating opacity. Don't do this
2386 : // if we're going to compute plugin geometry, since opacity-0 plugins
2387 : // need to have display items built for them.
2388 : bool needEventRegions =
2389 1168 : aBuilder->IsBuildingLayerEventRegions() &&
2390 553 : StyleUserInterface()->GetEffectivePointerEvents(this) !=
2391 615 : NS_STYLE_POINTER_EVENTS_NONE;
2392 615 : bool opacityItemForEventsAndPluginsOnly = false;
2393 1378 : if (effects->mOpacity == 0.0 && aBuilder->IsForPainting() &&
2394 763 : !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
2395 74 : !nsLayoutUtils::HasAnimationOfProperty(effectSet, eCSSProperty_opacity)) {
2396 76 : if (needEventRegions ||
2397 2 : aBuilder->WillComputePluginGeometry()) {
2398 72 : opacityItemForEventsAndPluginsOnly = true;
2399 : } else {
2400 2 : return;
2401 : }
2402 : }
2403 :
2404 613 : if (disp->mWillChangeBitField != 0) {
2405 0 : aBuilder->AddToWillChangeBudget(this, GetSize());
2406 : }
2407 :
2408 613 : bool extend3DContext = Extend3DContext(disp, effectSet);
2409 1226 : Maybe<nsDisplayListBuilder::AutoPreserves3DContext> autoPreserves3DContext;
2410 613 : if (extend3DContext && !Combines3DTransformWithAncestors(disp)) {
2411 : // Start a new preserves3d context to keep informations on
2412 : // nsDisplayListBuilder.
2413 0 : autoPreserves3DContext.emplace(aBuilder);
2414 : // Save dirty rect on the builder to avoid being distorted for
2415 : // multiple transforms along the chain.
2416 0 : aBuilder->SetPreserves3DDirtyRect(aDirtyRect);
2417 : }
2418 :
2419 : // For preserves3d, use the dirty rect already installed on the
2420 : // builder, since aDirtyRect maybe distorted for transforms along
2421 : // the chain.
2422 1226 : nsRect dirtyRect = aDirtyRect;
2423 :
2424 613 : bool inTransform = aBuilder->IsInTransform();
2425 613 : bool isTransformed = IsTransformed(disp, effectSet);
2426 613 : bool hasPerspective = HasPerspective(effectSet);
2427 : // reset blend mode so we can keep track if this stacking context needs have
2428 : // a nsDisplayBlendContainer. Set the blend mode back when the routine exits
2429 : // so we keep track if the parent stacking context needs a container too.
2430 1226 : AutoSaveRestoreContainsBlendMode autoRestoreBlendMode(*aBuilder);
2431 613 : aBuilder->SetContainsBlendMode(false);
2432 :
2433 1226 : nsRect dirtyRectOutsideTransform = dirtyRect;
2434 613 : bool allowAsyncAnimation = false;
2435 613 : if (isTransformed) {
2436 48 : const nsRect overflow = GetVisualOverflowRectRelativeToSelf();
2437 : nsDisplayTransform::PrerenderDecision decision =
2438 24 : nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder, this, &dirtyRect);
2439 24 : switch (decision) {
2440 : case nsDisplayTransform::FullPrerender:
2441 0 : allowAsyncAnimation = true;
2442 0 : break;
2443 : case nsDisplayTransform::PartialPrerender:
2444 0 : allowAsyncAnimation = true;
2445 : MOZ_FALLTHROUGH;
2446 : // fall through to the NoPrerender case
2447 : case nsDisplayTransform::NoPrerender:
2448 24 : if (overflow.IsEmpty() && !extend3DContext) {
2449 0 : return;
2450 : }
2451 :
2452 : // If we're in preserve-3d then grab the dirty rect that was given to the root
2453 : // and transform using the combined transform.
2454 24 : if (Combines3DTransformWithAncestors(disp)) {
2455 0 : dirtyRect = aBuilder->GetPreserves3DDirtyRect(this);
2456 : }
2457 :
2458 48 : nsRect untransformedDirtyRect;
2459 24 : if (nsDisplayTransform::UntransformRect(dirtyRect, overflow, this,
2460 : &untransformedDirtyRect)) {
2461 24 : dirtyRect = untransformedDirtyRect;
2462 : } else {
2463 0 : NS_WARNING("Unable to untransform dirty rect!");
2464 : // This should only happen if the transform is singular, in which case nothing is visible anyway
2465 0 : dirtyRect.SetEmpty();
2466 : }
2467 : }
2468 24 : inTransform = true;
2469 : }
2470 613 : bool usingFilter = StyleEffects()->HasFilters();
2471 613 : bool usingMask = nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(this);
2472 613 : bool usingSVGEffects = usingFilter || usingMask;
2473 :
2474 1226 : nsRect dirtyRectOutsideSVGEffects = dirtyRect;
2475 1226 : nsDisplayList hoistedScrollInfoItemsStorage;
2476 613 : if (usingSVGEffects) {
2477 7 : dirtyRect =
2478 14 : nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
2479 7 : aBuilder->EnterSVGEffectsContents(&hoistedScrollInfoItemsStorage);
2480 : }
2481 :
2482 : // We build an opacity item if it's not going to be drawn by SVG content, or
2483 : // SVG effects. SVG effects won't handle the opacity if we want an active
2484 : // layer (for async animations), see
2485 : // nsSVGIntegrationsUtils::PaintMaskAndClipPath or
2486 : // nsSVGIntegrationsUtils::PaintFilter.
2487 786 : bool useOpacity = HasVisualOpacity(effectSet) &&
2488 959 : !nsSVGUtils::CanOptimizeOpacity(this) &&
2489 786 : (!usingSVGEffects || nsDisplayOpacity::NeedsActiveLayer(aBuilder, this));
2490 613 : bool useBlendMode = effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL;
2491 613 : bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY &&
2492 0 : IsScrollFrameActive(aBuilder,
2493 0 : nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
2494 : nsLayoutUtils::SCROLLABLE_SAME_DOC |
2495 613 : nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
2496 696 : bool useFixedPosition = disp->mPosition == NS_STYLE_POSITION_FIXED &&
2497 779 : (nsLayoutUtils::IsFixedPosFrameInDisplayPort(this) || BuilderHasScrolledClip(aBuilder));
2498 :
2499 : nsDisplayListBuilder::AutoBuildingDisplayList
2500 1226 : buildingDisplayList(aBuilder, this, dirtyRect, true);
2501 :
2502 : // Depending on the effects that are applied to this frame, we can create
2503 : // multiple container display items and wrap them around our contents.
2504 : // This enum lists all the potential container display items, in the order
2505 : // outside to inside.
2506 : enum class ContainerItemType : uint8_t {
2507 : eNone = 0,
2508 : eOwnLayerIfNeeded,
2509 : eBlendMode,
2510 : eFixedPosition,
2511 : eOwnLayerForTransformWithRoundedClip,
2512 : ePerspective,
2513 : eTransform,
2514 : eSeparatorTransforms,
2515 : eOpacity,
2516 : eFilter,
2517 : eBlendContainer
2518 : };
2519 :
2520 1226 : nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
2521 :
2522 1226 : DisplayListClipState::AutoSaveRestore clipState(aBuilder);
2523 :
2524 : // If there is a current clip, then depending on the container items we
2525 : // create, different things can happen to it. Some container items simply
2526 : // propagate the clip to their children and aren't clipped themselves.
2527 : // But other container items, especially those that establish a different
2528 : // geometry for their contents (e.g. transforms), capture the clip on
2529 : // themselves and unset the clip for their contents. If we create more than
2530 : // one of those container items, the clip will be captured on the outermost
2531 : // one and the inner container items will be unclipped.
2532 613 : ContainerItemType clipCapturedBy = ContainerItemType::eNone;
2533 613 : if (useFixedPosition) {
2534 0 : clipCapturedBy = ContainerItemType::eFixedPosition;
2535 613 : } else if (isTransformed) {
2536 : const DisplayItemClipChain* currentClip =
2537 24 : aBuilder->ClipState().GetCurrentCombinedClipChain(aBuilder);
2538 24 : if ((hasPerspective || extend3DContext) &&
2539 0 : (currentClip && currentClip->HasRoundedCorners())) {
2540 : // If we're creating an nsDisplayTransform item that is going to combine
2541 : // its transform with its children (preserve-3d or perspective), then we
2542 : // can't have an intermediate surface. Mask layers force an intermediate
2543 : // surface, so if we're going to need both then create a separate
2544 : // wrapping layer for the mask.
2545 0 : clipCapturedBy = ContainerItemType::eOwnLayerForTransformWithRoundedClip;
2546 24 : } else if (hasPerspective) {
2547 0 : clipCapturedBy = ContainerItemType::ePerspective;
2548 : } else {
2549 24 : clipCapturedBy = ContainerItemType::eTransform;
2550 : }
2551 589 : } else if (usingFilter) {
2552 0 : clipCapturedBy = ContainerItemType::eFilter;
2553 : }
2554 :
2555 613 : if (clipCapturedBy != ContainerItemType::eNone) {
2556 24 : clipState.Clear();
2557 : }
2558 :
2559 1226 : nsDisplayListCollection set;
2560 : {
2561 1226 : DisplayListClipState::AutoSaveRestore nestedClipState(aBuilder);
2562 : nsDisplayListBuilder::AutoInTransformSetter
2563 1226 : inTransformSetter(aBuilder, inTransform);
2564 : nsDisplayListBuilder::AutoSaveRestorePerspectiveIndex
2565 1226 : perspectiveIndex(aBuilder, this);
2566 :
2567 613 : CheckForApzAwareEventHandlers(aBuilder, this);
2568 :
2569 : Maybe<nsRect> contentClip =
2570 1226 : GetClipPropClipRect(disp, effects, GetSize());
2571 :
2572 613 : if (contentClip) {
2573 0 : dirtyRect.IntersectRect(dirtyRect, *contentClip);
2574 0 : nestedClipState.ClipContentDescendants(*contentClip +
2575 0 : aBuilder->ToReferenceFrame(this));
2576 : }
2577 :
2578 : // extend3DContext also guarantees that applyAbsPosClipping and usingSVGEffects are false
2579 : // We only modify the preserve-3d rect if we are the top of a preserve-3d heirarchy
2580 613 : if (extend3DContext) {
2581 : // Mark these first so MarkAbsoluteFramesForDisplayList knows if we are
2582 : // going to be forced to descend into frames.
2583 0 : aBuilder->MarkPreserve3DFramesForDisplayList(this);
2584 : }
2585 :
2586 613 : MarkAbsoluteFramesForDisplayList(aBuilder, dirtyRect);
2587 :
2588 613 : nsDisplayLayerEventRegions* eventRegions = nullptr;
2589 613 : if (aBuilder->IsBuildingLayerEventRegions()) {
2590 551 : eventRegions = new (aBuilder) nsDisplayLayerEventRegions(aBuilder, this);
2591 551 : eventRegions->AddFrame(aBuilder, this);
2592 551 : aBuilder->SetLayerEventRegions(eventRegions);
2593 : }
2594 613 : aBuilder->AdjustWindowDraggingRegion(this);
2595 613 : BuildDisplayList(aBuilder, dirtyRect, set);
2596 613 : if (eventRegions) {
2597 : // If the event regions item ended up empty, throw it away rather than
2598 : // adding it to the display list.
2599 551 : if (!eventRegions->IsEmpty()) {
2600 413 : set.BorderBackground()->AppendToBottom(eventRegions);
2601 : } else {
2602 138 : aBuilder->SetLayerEventRegions(nullptr);
2603 138 : eventRegions->~nsDisplayLayerEventRegions();
2604 138 : eventRegions = nullptr;
2605 : }
2606 : }
2607 : }
2608 :
2609 613 : if (aBuilder->IsBackgroundOnly()) {
2610 0 : set.BlockBorderBackgrounds()->DeleteAll();
2611 0 : set.Floats()->DeleteAll();
2612 0 : set.Content()->DeleteAll();
2613 0 : set.PositionedDescendants()->DeleteAll();
2614 0 : set.Outlines()->DeleteAll();
2615 : }
2616 :
2617 : // Sort PositionedDescendants() in CSS 'z-order' order. The list is already
2618 : // in content document order and SortByZOrder is a stable sort which
2619 : // guarantees that boxes produced by the same element are placed together
2620 : // in the sort. Consider a position:relative inline element that breaks
2621 : // across lines and has absolutely positioned children; all the abs-pos
2622 : // children should be z-ordered after all the boxes for the position:relative
2623 : // element itself.
2624 613 : set.PositionedDescendants()->SortByZOrder();
2625 :
2626 1226 : nsDisplayList resultList;
2627 : // Now follow the rules of http://www.w3.org/TR/CSS21/zindex.html
2628 : // 1,2: backgrounds and borders
2629 613 : resultList.AppendToTop(set.BorderBackground());
2630 : // 3: negative z-index children.
2631 : for (;;) {
2632 637 : nsDisplayItem* item = set.PositionedDescendants()->GetBottom();
2633 637 : if (item && item->ZIndex() < 0) {
2634 24 : set.PositionedDescendants()->RemoveBottom();
2635 24 : resultList.AppendToTop(item);
2636 24 : continue;
2637 : }
2638 613 : break;
2639 24 : }
2640 : // 4: block backgrounds
2641 613 : resultList.AppendToTop(set.BlockBorderBackgrounds());
2642 : // 5: floats
2643 613 : resultList.AppendToTop(set.Floats());
2644 : // 7: general content
2645 613 : resultList.AppendToTop(set.Content());
2646 : // 7.5: outlines, in content tree order. We need to sort by content order
2647 : // because an element with outline that breaks and has children with outline
2648 : // might have placed child outline items between its own outline items.
2649 : // The element's outline items need to all come before any child outline
2650 : // items.
2651 613 : nsIContent* content = GetContent();
2652 613 : if (!content) {
2653 53 : content = PresContext()->Document()->GetRootElement();
2654 : }
2655 613 : if (content) {
2656 613 : set.Outlines()->SortByContentOrder(content);
2657 : }
2658 : #ifdef DEBUG
2659 613 : DisplayDebugBorders(aBuilder, this, set);
2660 : #endif
2661 613 : resultList.AppendToTop(set.Outlines());
2662 : // 8, 9: non-negative z-index children
2663 613 : resultList.AppendToTop(set.PositionedDescendants());
2664 :
2665 : // Get the ASR to use for the container items that we create here.
2666 613 : const ActiveScrolledRoot* containerItemASR = contASRTracker.GetContainerASR();
2667 :
2668 : /* If adding both a nsDisplayBlendContainer and a nsDisplayBlendMode to the
2669 : * same list, the nsDisplayBlendContainer should be added first. This only
2670 : * happens when the element creating this stacking context has mix-blend-mode
2671 : * and also contains a child which has mix-blend-mode.
2672 : * The nsDisplayBlendContainer must be added to the list first, so it does not
2673 : * isolate the containing element blending as well.
2674 : */
2675 613 : if (aBuilder->ContainsBlendMode()) {
2676 0 : DisplayListClipState::AutoSaveRestore blendContainerClipState(aBuilder);
2677 0 : blendContainerClipState.ClearUpToASR(containerItemASR);
2678 0 : resultList.AppendNewToTop(
2679 0 : nsDisplayBlendContainer::CreateForMixBlendMode(aBuilder, this, &resultList,
2680 0 : containerItemASR));
2681 : }
2682 :
2683 : /* If there are any SVG effects, wrap the list up in an SVG effects item
2684 : * (which also handles CSS group opacity). Note that we create an SVG effects
2685 : * item even if resultList is empty, since a filter can produce graphical
2686 : * output even if the element being filtered wouldn't otherwise do so.
2687 : */
2688 613 : if (usingSVGEffects) {
2689 7 : MOZ_ASSERT(usingFilter ||usingMask,
2690 : "Beside filter & mask/clip-path, what else effect do we have?");
2691 :
2692 7 : if (clipCapturedBy == ContainerItemType::eFilter) {
2693 0 : clipState.Restore();
2694 : }
2695 : // Revert to the post-filter dirty rect.
2696 7 : buildingDisplayList.SetDirtyRect(dirtyRectOutsideSVGEffects);
2697 :
2698 : // Skip all filter effects while generating glyph mask.
2699 7 : if (usingFilter && !aBuilder->IsForGenerateGlyphMask()) {
2700 : // If we are going to create a mask display item, handle opacity effect
2701 : // in that mask display item; Otherwise, take care of opacity in this
2702 : // filter display item.
2703 0 : bool handleOpacity = !usingMask && !useOpacity;
2704 :
2705 : /* List now emptied, so add the new list to the top. */
2706 : resultList.AppendNewToTop(
2707 : new (aBuilder) nsDisplayFilter(aBuilder, this, &resultList,
2708 0 : handleOpacity));
2709 : }
2710 :
2711 7 : if (usingMask) {
2712 14 : DisplayListClipState::AutoSaveRestore maskClipState(aBuilder);
2713 7 : maskClipState.ClearUpToASR(containerItemASR);
2714 : /* List now emptied, so add the new list to the top. */
2715 : resultList.AppendNewToTop(
2716 : new (aBuilder) nsDisplayMask(aBuilder, this, &resultList,
2717 7 : !useOpacity, containerItemASR));
2718 : }
2719 :
2720 : // Also add the hoisted scroll info items. We need those for APZ scrolling
2721 : // because nsDisplayMask items can't build active layers.
2722 7 : aBuilder->ExitSVGEffectsContents();
2723 7 : resultList.AppendToTop(&hoistedScrollInfoItemsStorage);
2724 : }
2725 :
2726 : /* If the list is non-empty and there is CSS group opacity without SVG
2727 : * effects, wrap it up in an opacity item.
2728 : */
2729 613 : if (useOpacity && !resultList.IsEmpty()) {
2730 : // Don't clip nsDisplayOpacity items. We clip their descendants instead.
2731 : // The clip we would set on an element with opacity would clip
2732 : // all descendant content, but some should not be clipped.
2733 346 : DisplayListClipState::AutoSaveRestore opacityClipState(aBuilder);
2734 173 : opacityClipState.ClearUpToASR(containerItemASR);
2735 : resultList.AppendNewToTop(
2736 : new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList,
2737 : containerItemASR,
2738 173 : opacityItemForEventsAndPluginsOnly));
2739 : }
2740 :
2741 : /* If we're going to apply a transformation and don't have preserve-3d set, wrap
2742 : * everything in an nsDisplayTransform. If there's nothing in the list, don't add
2743 : * anything.
2744 : *
2745 : * For the preserve-3d case we want to individually wrap every child in the list with
2746 : * a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform,
2747 : * we can skip this step, as the computed transform will already include our own.
2748 : *
2749 : * We also traverse into sublists created by nsDisplayWrapList, so that we find all the
2750 : * correct children.
2751 : */
2752 613 : if (isTransformed && !resultList.IsEmpty() && extend3DContext) {
2753 : // Install dummy nsDisplayTransform as a leaf containing
2754 : // descendants not participating this 3D rendering context.
2755 0 : nsDisplayList nonparticipants;
2756 0 : nsDisplayList participants;
2757 0 : int index = 1;
2758 :
2759 0 : while (nsDisplayItem* item = resultList.RemoveBottom()) {
2760 0 : if (ItemParticipatesIn3DContext(this, item) && !item->GetClip().HasClip()) {
2761 : // The frame of this item participates the same 3D context.
2762 0 : WrapSeparatorTransform(aBuilder, this, dirtyRect,
2763 0 : &nonparticipants, &participants, index++);
2764 0 : participants.AppendToTop(item);
2765 : } else {
2766 : // The frame of the item doesn't participate the current
2767 : // context, or has no transform.
2768 : //
2769 : // For items participating but not transformed, they are add
2770 : // to nonparticipants to get a separator layer for handling
2771 : // clips, if there is, on an intermediate surface.
2772 : // \see ContainerLayer::DefaultComputeEffectiveTransforms().
2773 0 : nonparticipants.AppendToTop(item);
2774 : }
2775 0 : }
2776 0 : WrapSeparatorTransform(aBuilder, this, dirtyRect,
2777 0 : &nonparticipants, &participants, index++);
2778 0 : resultList.AppendToTop(&participants);
2779 : }
2780 :
2781 613 : if (isTransformed && !resultList.IsEmpty()) {
2782 24 : if (clipCapturedBy == ContainerItemType::eTransform) {
2783 : // Restore clip state now so nsDisplayTransform is clipped properly.
2784 24 : clipState.Restore();
2785 : }
2786 : // Revert to the dirtyrect coming in from the parent, without our transform
2787 : // taken into account.
2788 24 : buildingDisplayList.SetDirtyRect(dirtyRectOutsideTransform);
2789 : // Revert to the outer reference frame and offset because all display
2790 : // items we create from now on are outside the transform.
2791 24 : nsPoint toOuterReferenceFrame;
2792 24 : const nsIFrame* outerReferenceFrame = this;
2793 24 : if (this != aBuilder->RootReferenceFrame()) {
2794 : outerReferenceFrame =
2795 24 : aBuilder->FindReferenceFrameFor(GetParent(), &toOuterReferenceFrame);
2796 : }
2797 : buildingDisplayList.SetReferenceFrameAndCurrentOffset(outerReferenceFrame,
2798 24 : GetOffsetToCrossDoc(outerReferenceFrame));
2799 :
2800 48 : if (!aBuilder->IsForGenerateGlyphMask() &&
2801 24 : !aBuilder->IsForPaintingSelectionBG()) {
2802 : nsDisplayTransform *transformItem =
2803 : new (aBuilder) nsDisplayTransform(aBuilder, this,
2804 : &resultList, dirtyRect, 0,
2805 24 : allowAsyncAnimation);
2806 24 : resultList.AppendNewToTop(transformItem);
2807 : }
2808 :
2809 24 : if (hasPerspective) {
2810 0 : if (clipCapturedBy == ContainerItemType::ePerspective) {
2811 0 : clipState.Restore();
2812 : }
2813 : resultList.AppendNewToTop(
2814 : new (aBuilder) nsDisplayPerspective(
2815 : aBuilder, this,
2816 0 : GetContainingBlock(0, disp)->GetContent()->GetPrimaryFrame(),
2817 0 : &resultList));
2818 : }
2819 : }
2820 :
2821 613 : if (clipCapturedBy == ContainerItemType::eOwnLayerForTransformWithRoundedClip) {
2822 0 : clipState.Restore();
2823 0 : resultList.AppendNewToTop(
2824 : new (aBuilder) nsDisplayOwnLayer(aBuilder, this, &resultList,
2825 0 : aBuilder->CurrentActiveScrolledRoot(), 0,
2826 : mozilla::layers::FrameMetrics::NULL_SCROLL_ID,
2827 0 : ScrollThumbData{}, /* aForceActive = */ false));
2828 : }
2829 :
2830 : /* If we have sticky positioning, wrap it in a sticky position item.
2831 : */
2832 613 : if (useFixedPosition) {
2833 0 : if (clipCapturedBy == ContainerItemType::eFixedPosition) {
2834 0 : clipState.Restore();
2835 : }
2836 : // The ASR for the fixed item should be the ASR of our containing block,
2837 : // which has been set as the builder's current ASR, unless this frame is
2838 : // invisible and we hadn't saved display item data for it. In that case,
2839 : // we need to take the containerItemASR since we might have fixed children.
2840 : const ActiveScrolledRoot* fixedASR =
2841 0 : ActiveScrolledRoot::PickAncestor(containerItemASR, aBuilder->CurrentActiveScrolledRoot());
2842 : resultList.AppendNewToTop(
2843 0 : new (aBuilder) nsDisplayFixedPosition(aBuilder, this, &resultList, fixedASR));
2844 613 : } else if (useStickyPosition) {
2845 : // For position:sticky, the clip needs to be applied both to the sticky
2846 : // container item and to the contents. The container item needs the clip
2847 : // because a scrolled clip needs to move independently from the sticky
2848 : // contents, and the contents need the clip so that they have finite
2849 : // clipped bounds with respect to the container item's ASR. The latter is
2850 : // a little tricky in the case where the sticky item has both fixed and
2851 : // non-fixed descendants, because that means that the sticky container
2852 : // item's ASR is the ASR of the fixed descendant.
2853 : const ActiveScrolledRoot* stickyASR =
2854 0 : ActiveScrolledRoot::PickAncestor(containerItemASR, aBuilder->CurrentActiveScrolledRoot());
2855 : resultList.AppendNewToTop(
2856 0 : new (aBuilder) nsDisplayStickyPosition(aBuilder, this, &resultList, stickyASR));
2857 : }
2858 :
2859 : /* If there's blending, wrap up the list in a blend-mode item. Note
2860 : * that opacity can be applied before blending as the blend color is
2861 : * not affected by foreground opacity (only background alpha).
2862 : */
2863 :
2864 613 : if (useBlendMode && !resultList.IsEmpty()) {
2865 0 : DisplayListClipState::AutoSaveRestore blendModeClipState(aBuilder);
2866 0 : blendModeClipState.ClearUpToASR(containerItemASR);
2867 : resultList.AppendNewToTop(
2868 : new (aBuilder) nsDisplayBlendMode(aBuilder, this, &resultList,
2869 0 : effects->mMixBlendMode,
2870 0 : containerItemASR));
2871 : }
2872 :
2873 613 : CreateOwnLayerIfNeeded(aBuilder, &resultList);
2874 :
2875 613 : aList->AppendToTop(&resultList);
2876 : }
2877 :
2878 : static nsDisplayItem*
2879 606 : WrapInWrapList(nsDisplayListBuilder* aBuilder,
2880 : nsIFrame* aFrame, nsDisplayList* aList,
2881 : const ActiveScrolledRoot* aContainerASR)
2882 : {
2883 606 : nsDisplayItem* item = aList->GetBottom();
2884 606 : if (!item) {
2885 0 : return nullptr;
2886 : }
2887 :
2888 : // For perspective items we want to treat the 'frame' as being the transform
2889 : // frame that created it. This stops the transform frame from wrapping another
2890 : // nsDisplayWrapList around it (with mismatching reference frames), but still
2891 : // makes the perspective frame create one (so we have an atomic entry for z-index
2892 : // sorting).
2893 606 : nsIFrame *itemFrame = item->Frame();
2894 606 : if (item->GetType() == nsDisplayItem::TYPE_PERSPECTIVE) {
2895 0 : itemFrame = static_cast<nsDisplayPerspective*>(item)->TransformFrame();
2896 : }
2897 :
2898 606 : if (item->GetAbove() || itemFrame != aFrame) {
2899 321 : return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList, aContainerASR);
2900 : }
2901 285 : aList->RemoveBottom();
2902 285 : return item;
2903 : }
2904 :
2905 : /**
2906 : * Check if a frame should be visited for building display list.
2907 : */
2908 : static bool
2909 4147 : DescendIntoChild(nsDisplayListBuilder* aBuilder, nsIFrame *aChild,
2910 : const nsRect& aDirty)
2911 : {
2912 4147 : nsIFrame* child = aChild;
2913 4147 : const nsRect& dirty = aDirty;
2914 :
2915 4147 : if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) {
2916 : // No need to descend into child to catch placeholders for visible
2917 : // positioned stuff. So see if we can short-circuit frame traversal here.
2918 :
2919 : // We can stop if child's frame subtree's intersection with the
2920 : // dirty area is empty.
2921 : // If the child is a scrollframe that we want to ignore, then we need
2922 : // to descend into it because its scrolled child may intersect the dirty
2923 : // area even if the scrollframe itself doesn't.
2924 : // There are cases where the "ignore scroll frame" on the builder is not set
2925 : // correctly, and so we additionally want to catch cases where the child is
2926 : // a root scrollframe and we are ignoring scrolling on the viewport.
2927 3513 : nsIPresShell* shell = child->PresContext()->PresShell();
2928 7026 : bool keepDescending = child == aBuilder->GetIgnoreScrollFrame() ||
2929 7131 : (shell->IgnoringViewportScrolling() && child == shell->GetRootScrollFrame());
2930 3513 : if (!keepDescending) {
2931 5926 : nsRect childDirty;
2932 3495 : if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect()))
2933 1064 : return false;
2934 : // Usually we could set dirty to childDirty now but there's no
2935 : // benefit, and it can be confusing. It can especially confuse
2936 : // situations where we're going to ignore a scrollframe's clipping;
2937 : // we wouldn't want to clip the dirty area to the scrollframe's
2938 : // bounds in that case.
2939 : }
2940 : }
2941 3083 : return true;
2942 : }
2943 :
2944 : void
2945 4717 : nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
2946 : nsIFrame* aChild,
2947 : const nsRect& aDirtyRect,
2948 : const nsDisplayListSet& aLists,
2949 : uint32_t aFlags) {
2950 : // If painting is restricted to just the background of the top level frame,
2951 : // then we have nothing to do here.
2952 4717 : if (aBuilder->IsBackgroundOnly())
2953 4026 : return;
2954 :
2955 9434 : if (aBuilder->IsForGenerateGlyphMask() ||
2956 4717 : aBuilder->IsForPaintingSelectionBG()) {
2957 0 : if (!aChild->IsTextFrame() && aChild->IsLeaf()) {
2958 0 : return;
2959 : }
2960 : }
2961 :
2962 4717 : nsIFrame* child = aChild;
2963 4717 : if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
2964 0 : return;
2965 :
2966 : const bool doingShortcut =
2967 6562 : (child->GetStateBits() & NS_FRAME_SIMPLE_DISPLAYLIST) &&
2968 3564 : aBuilder->IsPaintingToWindow() &&
2969 : // This would be changed by the change of preference.
2970 9874 : aBuilder->IsBuildingLayerEventRegions() &&
2971 : // Animations may change the value of |HasOpacity()|.
2972 3438 : !(child->GetContent() &&
2973 6436 : child->GetContent()->MayHaveAnimations());
2974 4717 : if (doingShortcut) {
2975 : // This is the shortcut for frames been handled along the common
2976 : // path, the most common one of THE COMMON CASE mentioned later.
2977 1719 : MOZ_ASSERT(child->Type() != LayoutFrameType::Placeholder);
2978 1719 : MOZ_ASSERT(!aBuilder->GetSelectedFramesOnly() &&
2979 : !aBuilder->GetIncludeAllOutOfFlows(),
2980 : "It should be held for painting to window");
2981 :
2982 : // dirty rect in child-relative coordinates
2983 3438 : nsRect dirty = aDirtyRect - child->GetOffsetTo(this);
2984 1719 : if (!DescendIntoChild(aBuilder, child, dirty)) {
2985 0 : return;
2986 : }
2987 :
2988 : nsDisplayListBuilder::AutoBuildingDisplayList
2989 3438 : buildingForChild(aBuilder, child, dirty, false);
2990 :
2991 1719 : CheckForApzAwareEventHandlers(aBuilder, child);
2992 :
2993 1719 : nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
2994 1719 : if (eventRegions) {
2995 1719 : eventRegions->AddFrame(aBuilder, child);
2996 : }
2997 :
2998 1719 : child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
2999 1719 : aBuilder->AdjustWindowDraggingRegion(child);
3000 1719 : child->BuildDisplayList(aBuilder, dirty, aLists);
3001 1719 : aBuilder->DisplayCaret(child, dirty, aLists.Content());
3002 : #ifdef DEBUG
3003 1719 : DisplayDebugBorders(aBuilder, child, aLists);
3004 : #endif
3005 1719 : return;
3006 : }
3007 :
3008 2998 : bool isSVG = (child->GetStateBits() & NS_FRAME_SVG_LAYOUT);
3009 :
3010 : // It is raised if the control flow strays off the common path.
3011 : // The common path is the most common one of THE COMMON CASE
3012 : // mentioned later.
3013 2998 : bool awayFromCommonPath = false;
3014 :
3015 : // true if this is a real or pseudo stacking context
3016 : bool pseudoStackingContext =
3017 2998 : (aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0;
3018 2998 : awayFromCommonPath |= pseudoStackingContext;
3019 8911 : if (!isSVG &&
3020 3041 : (aFlags & DISPLAY_CHILD_INLINE) &&
3021 43 : !child->IsFrameOfType(eLineParticipant)) {
3022 : // child is a non-inline frame in an inline context, i.e.,
3023 : // it acts like inline-block or inline-table. Therefore it is a
3024 : // pseudo-stacking-context.
3025 35 : pseudoStackingContext = true;
3026 35 : awayFromCommonPath = true;
3027 : }
3028 :
3029 : // dirty rect in child-relative coordinates
3030 3689 : nsRect dirty = aDirtyRect - child->GetOffsetTo(this);
3031 :
3032 2998 : nsDisplayListBuilder::OutOfFlowDisplayData* savedOutOfFlowData = nullptr;
3033 2998 : bool isPlaceholder = false;
3034 2998 : if (child->IsPlaceholderFrame()) {
3035 655 : isPlaceholder = true;
3036 655 : nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(child);
3037 655 : child = placeholder->GetOutOfFlowFrame();
3038 655 : NS_ASSERTION(child, "No out of flow frame?");
3039 : // If 'child' is a pushed float then it's owned by a block that's not an
3040 : // ancestor of the placeholder, and it will be painted by that block and
3041 : // should not be painted through the placeholder.
3042 740 : if (!child || nsLayoutUtils::IsPopup(child) ||
3043 85 : (child->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT))
3044 570 : return;
3045 85 : MOZ_ASSERT(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW);
3046 : // If the out-of-flow frame is in the top layer, the viewport frame
3047 : // will paint it. Skip it here. Note that, only out-of-flow frames
3048 : // with this property should be skipped, because non-HTML elements
3049 : // may stop their children from being out-of-flow. Those frames
3050 : // should still be handled in the normal in-flow path.
3051 85 : if (placeholder->GetStateBits() & PLACEHOLDER_FOR_TOPLAYER) {
3052 0 : return;
3053 : }
3054 : // Recheck NS_FRAME_TOO_DEEP_IN_FRAME_TREE
3055 85 : if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
3056 0 : return;
3057 85 : savedOutOfFlowData = nsDisplayListBuilder::GetOutOfFlowData(child);
3058 85 : if (savedOutOfFlowData) {
3059 85 : dirty = savedOutOfFlowData->mDirtyRect;
3060 : } else {
3061 : // The out-of-flow frame did not intersect the dirty area. We may still
3062 : // need to traverse into it, since it may contain placeholders we need
3063 : // to enter to reach other out-of-flow frames that are visible.
3064 0 : dirty.SetEmpty();
3065 : }
3066 85 : pseudoStackingContext = true;
3067 85 : awayFromCommonPath = true;
3068 : }
3069 :
3070 2428 : NS_ASSERTION(!child->IsPlaceholderFrame(),
3071 : "Should have dealt with placeholders already");
3072 4856 : if (aBuilder->GetSelectedFramesOnly() &&
3073 2428 : child->IsLeaf() &&
3074 0 : !aChild->IsSelected()) {
3075 0 : return;
3076 : }
3077 :
3078 2428 : if (aBuilder->GetIncludeAllOutOfFlows() &&
3079 0 : (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
3080 0 : dirty = child->GetVisualOverflowRect();
3081 0 : awayFromCommonPath = true;
3082 2428 : } else if (!DescendIntoChild(aBuilder, child, dirty)) {
3083 1064 : return;
3084 : }
3085 :
3086 : // XXX need to have inline-block and inline-table set pseudoStackingContext
3087 :
3088 1364 : const nsStyleDisplay* ourDisp = StyleDisplay();
3089 : // REVIEW: Taken from nsBoxFrame::Paint
3090 : // Don't paint our children if the theme object is a leaf.
3091 1445 : if (IsThemed(ourDisp) &&
3092 81 : !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance))
3093 0 : return;
3094 :
3095 : // Since we're now sure that we're adding this frame to the display list
3096 : // (which means we're painting it, modulo occlusion), mark it as visible
3097 : // within the displayport.
3098 1364 : if (aBuilder->IsPaintingToWindow() && child->TrackingVisibility()) {
3099 0 : child->PresContext()->PresShell()->EnsureFrameInApproximatelyVisibleList(child);
3100 0 : awayFromCommonPath = true;
3101 : }
3102 :
3103 : // Child is composited if it's transformed, partially transparent, or has
3104 : // SVG effects or a blend mode..
3105 1364 : EffectSet* effectSet = EffectSet::GetEffectSet(child);
3106 1364 : const nsStyleDisplay* disp = child->StyleDisplay();
3107 1364 : const nsStyleEffects* effects = child->StyleEffects();
3108 1364 : const nsStylePosition* pos = child->StylePosition();
3109 1364 : bool isVisuallyAtomic = child->HasOpacity(effectSet)
3110 1168 : || child->IsTransformed(disp, effectSet)
3111 : // strictly speaking, 'perspective' doesn't require visual atomicity,
3112 : // but the spec says it acts like the rest of these
3113 1144 : || disp->mChildPerspective.GetUnit() == eStyleUnit_Coord
3114 1144 : || effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL
3115 2508 : || nsSVGIntegrationUtils::UsingEffectsForFrame(child);
3116 :
3117 1364 : bool isPositioned = disp->IsAbsPosContainingBlock(child);
3118 : bool isStackingContext =
3119 565 : (isPositioned && (disp->IsPositionForcingStackingContext() ||
3120 1375 : pos->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
3121 2270 : (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
3122 2270 : disp->mIsolation != NS_STYLE_ISOLATION_AUTO ||
3123 2274 : isVisuallyAtomic || (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT);
3124 :
3125 3317 : if (isVisuallyAtomic || isPositioned || (!isSVG && disp->IsFloating(child)) ||
3126 816 : ((effects->mClipFlags & NS_STYLE_CLIP_RECT) &&
3127 816 : IsSVGContentWithCSSClip(child)) ||
3128 1632 : disp->mIsolation != NS_STYLE_ISOLATION_AUTO ||
3129 2996 : (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
3130 816 : (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
3131 : // If you change this, also change IsPseudoStackingContextFromStyle()
3132 677 : pseudoStackingContext = true;
3133 677 : awayFromCommonPath = true;
3134 : }
3135 1364 : NS_ASSERTION(!isStackingContext || pseudoStackingContext,
3136 : "Stacking contexts must also be pseudo-stacking-contexts");
3137 :
3138 : nsDisplayListBuilder::AutoBuildingDisplayList
3139 2055 : buildingForChild(aBuilder, child, dirty, pseudoStackingContext);
3140 2055 : DisplayListClipState::AutoClipMultiple clipState(aBuilder);
3141 2055 : nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter asrSetter(aBuilder);
3142 1364 : CheckForApzAwareEventHandlers(aBuilder, child);
3143 :
3144 1364 : if (savedOutOfFlowData) {
3145 85 : aBuilder->SetBuildingInvisibleItems(false);
3146 :
3147 85 : clipState.SetClipChainForContainingBlockDescendants(
3148 85 : savedOutOfFlowData->mContainingBlockClipChain);
3149 85 : asrSetter.SetCurrentActiveScrolledRoot(
3150 85 : savedOutOfFlowData->mContainingBlockActiveScrolledRoot);
3151 85 : MOZ_ASSERT(awayFromCommonPath, "It is impossible when savedOutOfFlowData is true");
3152 1279 : } else if (GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO &&
3153 : isPlaceholder) {
3154 0 : NS_ASSERTION(dirty.IsEmpty(), "should have empty dirty rect");
3155 : // Every item we build from now until we descent into an out of flow that
3156 : // does have saved out of flow data should be invisible. This state gets
3157 : // restored when AutoBuildingDisplayList gets out of scope.
3158 0 : aBuilder->SetBuildingInvisibleItems(true);
3159 :
3160 : // If we have nested out-of-flow frames and the outer one isn't visible
3161 : // then we won't have stored clip data for it. We can just clear the clip
3162 : // instead since we know we won't render anything, and the inner out-of-flow
3163 : // frame will setup the correct clip for itself.
3164 0 : clipState.SetClipChainForContainingBlockDescendants(nullptr);
3165 0 : awayFromCommonPath = true;
3166 : }
3167 :
3168 : // Setup clipping for the parent's overflow:-moz-hidden-unscrollable,
3169 : // or overflow:hidden on elements that don't support scrolling (and therefore
3170 : // don't create nsHTML/XULScrollFrame). This clipping needs to not clip
3171 : // anything directly rendered by the parent, only the rendering of its
3172 : // children.
3173 : // Don't use overflowClip to restrict the dirty rect, since some of the
3174 : // descendants may not be clipped by it. Even if we end up with unnecessary
3175 : // display items, they'll be pruned during ComputeVisibility.
3176 1364 : nsIFrame* parent = child->GetParent();
3177 : const nsStyleDisplay* parentDisp =
3178 1364 : parent == this ? ourDisp : parent->StyleDisplay();
3179 1364 : if (ApplyOverflowClipping(aBuilder, parent, parentDisp, clipState)) {
3180 59 : awayFromCommonPath = true;
3181 : }
3182 :
3183 2055 : nsDisplayList list;
3184 2055 : nsDisplayList extraPositionedDescendants;
3185 1364 : const ActiveScrolledRoot* wrapListASR = aBuilder->CurrentActiveScrolledRoot();
3186 1364 : if (isStackingContext) {
3187 583 : if (effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
3188 0 : aBuilder->SetContainsBlendMode(true);
3189 : }
3190 : // True stacking context.
3191 : // For stacking contexts, BuildDisplayListForStackingContext handles
3192 : // clipping and MarkAbsoluteFramesForDisplayList.
3193 1166 : nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
3194 583 : child->BuildDisplayListForStackingContext(aBuilder, dirty, &list);
3195 583 : wrapListASR = contASRTracker.GetContainerASR();
3196 583 : aBuilder->DisplayCaret(child, dirty, &list);
3197 : } else {
3198 : Maybe<nsRect> clipPropClip =
3199 889 : child->GetClipPropClipRect(disp, effects, child->GetSize());
3200 781 : if (clipPropClip) {
3201 0 : dirty.IntersectRect(dirty, *clipPropClip);
3202 : clipState.ClipContentDescendants(
3203 0 : *clipPropClip + aBuilder->ToReferenceFrame(child));
3204 0 : awayFromCommonPath = true;
3205 : }
3206 :
3207 781 : child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty);
3208 :
3209 781 : if (aBuilder->IsBuildingLayerEventRegions()) {
3210 : // If this frame has a different animated geometry root than its parent,
3211 : // make sure we accumulate event regions for its layer.
3212 544 : if (buildingForChild.IsAnimatedGeometryRoot() || isPositioned) {
3213 : nsDisplayLayerEventRegions* eventRegions =
3214 96 : new (aBuilder) nsDisplayLayerEventRegions(aBuilder, child);
3215 96 : eventRegions->AddFrame(aBuilder, child);
3216 96 : aBuilder->SetLayerEventRegions(eventRegions);
3217 :
3218 96 : if (isPositioned) {
3219 : // We need this nsDisplayLayerEventRegions to be sorted with the positioned
3220 : // elements as positioned elements will be sorted on top of normal elements
3221 94 : list.AppendNewToTop(eventRegions);
3222 : } else {
3223 2 : aLists.BorderBackground()->AppendNewToTop(eventRegions);
3224 : }
3225 : } else {
3226 448 : nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions();
3227 448 : if (eventRegions) {
3228 448 : eventRegions->AddFrame(aBuilder, child);
3229 : }
3230 1282 : if (!awayFromCommonPath &&
3231 834 : aBuilder->IsPaintingToWindow() &&
3232 386 : !buildingForChild.MaybeAnimatedGeometryRoot()) {
3233 : // The shortcut is available for the child for next time.
3234 157 : child->AddStateBits(NS_FRAME_SIMPLE_DISPLAYLIST);
3235 : }
3236 : }
3237 : }
3238 :
3239 781 : if (!pseudoStackingContext) {
3240 : // THIS IS THE COMMON CASE.
3241 : // Not a pseudo or real stacking context. Do the simple thing and
3242 : // return early.
3243 :
3244 673 : aBuilder->AdjustWindowDraggingRegion(child);
3245 673 : child->BuildDisplayList(aBuilder, dirty, aLists);
3246 673 : aBuilder->DisplayCaret(child, dirty, aLists.Content());
3247 : #ifdef DEBUG
3248 673 : DisplayDebugBorders(aBuilder, child, aLists);
3249 : #endif
3250 673 : return;
3251 : }
3252 :
3253 : // A pseudo-stacking context (e.g., a positioned element with z-index auto).
3254 : // We allow positioned descendants of the child to escape to our parent
3255 : // stacking context's positioned descendant list, because they might be
3256 : // z-index:non-auto
3257 216 : nsDisplayListCollection pseudoStack;
3258 108 : aBuilder->AdjustWindowDraggingRegion(child);
3259 216 : nsDisplayListBuilder::AutoContainerASRTracker contASRTracker(aBuilder);
3260 108 : child->BuildDisplayList(aBuilder, dirty, pseudoStack);
3261 108 : aBuilder->DisplayCaret(child, dirty, pseudoStack.Content());
3262 108 : wrapListASR = contASRTracker.GetContainerASR();
3263 :
3264 108 : list.AppendToTop(pseudoStack.BorderBackground());
3265 108 : list.AppendToTop(pseudoStack.BlockBorderBackgrounds());
3266 108 : list.AppendToTop(pseudoStack.Floats());
3267 108 : list.AppendToTop(pseudoStack.Content());
3268 108 : list.AppendToTop(pseudoStack.Outlines());
3269 108 : extraPositionedDescendants.AppendToTop(pseudoStack.PositionedDescendants());
3270 : #ifdef DEBUG
3271 108 : DisplayDebugBorders(aBuilder, child, aLists);
3272 : #endif
3273 : }
3274 :
3275 691 : buildingForChild.RestoreBuildingInvisibleItemsValue();
3276 :
3277 : // Clear clip rect for the construction of the items below. Since we're
3278 : // clipping all their contents, they themselves don't need to be clipped.
3279 691 : clipState.ClearUpToASR(wrapListASR);
3280 :
3281 834 : if (isPositioned || isVisuallyAtomic ||
3282 143 : (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) {
3283 : // Genuine stacking contexts, and positioned pseudo-stacking-contexts,
3284 : // go in this level.
3285 677 : if (!list.IsEmpty()) {
3286 606 : nsDisplayItem* item = WrapInWrapList(aBuilder, child, &list, wrapListASR);
3287 606 : if (isSVG) {
3288 24 : aLists.Content()->AppendNewToTop(item);
3289 : } else {
3290 582 : aLists.PositionedDescendants()->AppendNewToTop(item);
3291 : }
3292 677 : }
3293 14 : } else if (!isSVG && disp->IsFloating(child)) {
3294 0 : if (!list.IsEmpty()) {
3295 0 : aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list, wrapListASR));
3296 : }
3297 : } else {
3298 14 : aLists.Content()->AppendToTop(&list);
3299 : }
3300 : // We delay placing the positioned descendants of positioned frames to here,
3301 : // because in the absence of z-index this is the correct order for them.
3302 : // This doesn't affect correctness because the positioned descendants list
3303 : // is sorted by z-order and content in BuildDisplayListForStackingContext,
3304 : // but it means that sort routine needs to do less work.
3305 691 : aLists.PositionedDescendants()->AppendToTop(&extraPositionedDescendants);
3306 : }
3307 :
3308 : void
3309 3113 : nsIFrame::MarkAbsoluteFramesForDisplayList(nsDisplayListBuilder* aBuilder,
3310 : const nsRect& aDirtyRect)
3311 : {
3312 3113 : if (IsAbsoluteContainer()) {
3313 350 : aBuilder->MarkFramesForDisplayList(this, GetAbsoluteContainingBlock()->GetChildList(), aDirtyRect);
3314 : }
3315 3113 : }
3316 :
3317 : nsresult
3318 17 : nsFrame::GetContentForEvent(WidgetEvent* aEvent,
3319 : nsIContent** aContent)
3320 : {
3321 17 : nsIFrame* f = nsLayoutUtils::GetNonGeneratedAncestor(this);
3322 17 : *aContent = f->GetContent();
3323 17 : NS_IF_ADDREF(*aContent);
3324 17 : return NS_OK;
3325 : }
3326 :
3327 : void
3328 0 : nsFrame::FireDOMEvent(const nsAString& aDOMEventName, nsIContent *aContent)
3329 : {
3330 0 : nsIContent* target = aContent ? aContent : mContent;
3331 :
3332 0 : if (target) {
3333 : RefPtr<AsyncEventDispatcher> asyncDispatcher =
3334 0 : new AsyncEventDispatcher(target, aDOMEventName, true, false);
3335 0 : DebugOnly<nsresult> rv = asyncDispatcher->PostDOMEvent();
3336 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "AsyncEventDispatcher failed to dispatch");
3337 : }
3338 0 : }
3339 :
3340 : nsresult
3341 7 : nsFrame::HandleEvent(nsPresContext* aPresContext,
3342 : WidgetGUIEvent* aEvent,
3343 : nsEventStatus* aEventStatus)
3344 : {
3345 :
3346 7 : if (aEvent->mMessage == eMouseMove) {
3347 : // XXX If the second argument of HandleDrag() is WidgetMouseEvent,
3348 : // the implementation becomes simpler.
3349 4 : return HandleDrag(aPresContext, aEvent, aEventStatus);
3350 : }
3351 :
3352 9 : if ((aEvent->mClass == eMouseEventClass &&
3353 3 : aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton) ||
3354 0 : aEvent->mClass == eTouchEventClass) {
3355 3 : if (aEvent->mMessage == eMouseDown || aEvent->mMessage == eTouchStart) {
3356 0 : HandlePress(aPresContext, aEvent, aEventStatus);
3357 3 : } else if (aEvent->mMessage == eMouseUp || aEvent->mMessage == eTouchEnd) {
3358 0 : HandleRelease(aPresContext, aEvent, aEventStatus);
3359 : }
3360 : }
3361 3 : return NS_OK;
3362 : }
3363 :
3364 : NS_IMETHODIMP
3365 0 : nsFrame::GetDataForTableSelection(const nsFrameSelection* aFrameSelection,
3366 : nsIPresShell* aPresShell,
3367 : WidgetMouseEvent* aMouseEvent,
3368 : nsIContent** aParentContent,
3369 : int32_t* aContentOffset,
3370 : int32_t* aTarget)
3371 : {
3372 0 : if (!aFrameSelection || !aPresShell || !aMouseEvent || !aParentContent || !aContentOffset || !aTarget)
3373 0 : return NS_ERROR_NULL_POINTER;
3374 :
3375 0 : *aParentContent = nullptr;
3376 0 : *aContentOffset = 0;
3377 0 : *aTarget = 0;
3378 :
3379 0 : int16_t displaySelection = aPresShell->GetSelectionFlags();
3380 :
3381 0 : bool selectingTableCells = aFrameSelection->GetTableCellSelection();
3382 :
3383 : // DISPLAY_ALL means we're in an editor.
3384 : // If already in cell selection mode,
3385 : // continue selecting with mouse drag or end on mouse up,
3386 : // or when using shift key to extend block of cells
3387 : // (Mouse down does normal selection unless Ctrl/Cmd is pressed)
3388 : bool doTableSelection =
3389 0 : displaySelection == nsISelectionDisplay::DISPLAY_ALL && selectingTableCells &&
3390 0 : (aMouseEvent->mMessage == eMouseMove ||
3391 0 : (aMouseEvent->mMessage == eMouseUp &&
3392 0 : aMouseEvent->button == WidgetMouseEvent::eLeftButton) ||
3393 0 : aMouseEvent->IsShift());
3394 :
3395 0 : if (!doTableSelection)
3396 : {
3397 : // In Browser, special 'table selection' key must be pressed for table selection
3398 : // or when just Shift is pressed and we're already in table/cell selection mode
3399 : #ifdef XP_MACOSX
3400 : doTableSelection = aMouseEvent->IsMeta() || (aMouseEvent->IsShift() && selectingTableCells);
3401 : #else
3402 0 : doTableSelection = aMouseEvent->IsControl() || (aMouseEvent->IsShift() && selectingTableCells);
3403 : #endif
3404 : }
3405 0 : if (!doTableSelection)
3406 0 : return NS_OK;
3407 :
3408 : // Get the cell frame or table frame (or parent) of the current content node
3409 0 : nsIFrame *frame = this;
3410 0 : bool foundCell = false;
3411 0 : bool foundTable = false;
3412 :
3413 : // Get the limiting node to stop parent frame search
3414 0 : nsIContent* limiter = aFrameSelection->GetLimiter();
3415 :
3416 : // If our content node is an ancestor of the limiting node,
3417 : // we should stop the search right now.
3418 0 : if (limiter && nsContentUtils::ContentIsDescendantOf(limiter, GetContent()))
3419 0 : return NS_OK;
3420 :
3421 : //We don't initiate row/col selection from here now,
3422 : // but we may in future
3423 : //bool selectColumn = false;
3424 : //bool selectRow = false;
3425 :
3426 0 : while (frame)
3427 : {
3428 : // Check for a table cell by querying to a known CellFrame interface
3429 0 : nsITableCellLayout *cellElement = do_QueryFrame(frame);
3430 0 : if (cellElement)
3431 : {
3432 0 : foundCell = true;
3433 : //TODO: If we want to use proximity to top or left border
3434 : // for row and column selection, this is the place to do it
3435 0 : break;
3436 : }
3437 : else
3438 : {
3439 : // If not a cell, check for table
3440 : // This will happen when starting frame is the table or child of a table,
3441 : // such as a row (we were inbetween cells or in table border)
3442 0 : nsTableWrapperFrame *tableFrame = do_QueryFrame(frame);
3443 0 : if (tableFrame)
3444 : {
3445 0 : foundTable = true;
3446 : //TODO: How can we select row when along left table edge
3447 : // or select column when along top edge?
3448 0 : break;
3449 : } else {
3450 0 : frame = frame->GetParent();
3451 : // Stop if we have hit the selection's limiting content node
3452 0 : if (frame && frame->GetContent() == limiter)
3453 0 : break;
3454 : }
3455 : }
3456 : }
3457 : // We aren't in a cell or table
3458 0 : if (!foundCell && !foundTable) return NS_OK;
3459 :
3460 0 : nsIContent* tableOrCellContent = frame->GetContent();
3461 0 : if (!tableOrCellContent) return NS_ERROR_FAILURE;
3462 :
3463 0 : nsCOMPtr<nsIContent> parentContent = tableOrCellContent->GetParent();
3464 0 : if (!parentContent) return NS_ERROR_FAILURE;
3465 :
3466 0 : int32_t offset = parentContent->IndexOf(tableOrCellContent);
3467 : // Not likely?
3468 0 : if (offset < 0) return NS_ERROR_FAILURE;
3469 :
3470 : // Everything is OK -- set the return values
3471 0 : parentContent.forget(aParentContent);
3472 :
3473 0 : *aContentOffset = offset;
3474 :
3475 : #if 0
3476 : if (selectRow)
3477 : *aTarget = nsISelectionPrivate::TABLESELECTION_ROW;
3478 : else if (selectColumn)
3479 : *aTarget = nsISelectionPrivate::TABLESELECTION_COLUMN;
3480 : else
3481 : #endif
3482 0 : if (foundCell)
3483 0 : *aTarget = nsISelectionPrivate::TABLESELECTION_CELL;
3484 0 : else if (foundTable)
3485 0 : *aTarget = nsISelectionPrivate::TABLESELECTION_TABLE;
3486 :
3487 0 : return NS_OK;
3488 : }
3489 :
3490 : bool
3491 0 : nsIFrame::IsSelectable(StyleUserSelect* aSelectStyle) const
3492 : {
3493 : // it's ok if aSelectStyle is null
3494 :
3495 : // Like 'visibility', we must check all the parents: if a parent
3496 : // is not selectable, none of its children is selectable.
3497 : //
3498 : // The -moz-all value acts similarly: if a frame has 'user-select:-moz-all',
3499 : // all its children are selectable, even those with 'user-select:none'.
3500 : //
3501 : // As a result, if 'none' and '-moz-all' are not present in the frame hierarchy,
3502 : // aSelectStyle returns the first style that is not AUTO. If these values
3503 : // are present in the frame hierarchy, aSelectStyle returns the style of the
3504 : // topmost parent that has either 'none' or '-moz-all'.
3505 : //
3506 : // The -moz-text value acts as a way to override an ancestor's all/-moz-all value.
3507 : //
3508 : // For instance, if the frame hierarchy is:
3509 : // AUTO -> _MOZ_ALL -> NONE -> TEXT, the returned value is ALL
3510 : // AUTO -> _MOZ_ALL -> NONE -> _MOZ_TEXT, the returned value is TEXT.
3511 : // TEXT -> NONE -> AUTO -> _MOZ_ALL, the returned value is TEXT
3512 : // _MOZ_ALL -> TEXT -> AUTO -> AUTO, the returned value is ALL
3513 : // _MOZ_ALL -> _MOZ_TEXT -> AUTO -> AUTO, the returned value is TEXT.
3514 : // AUTO -> CELL -> TEXT -> AUTO, the returned value is TEXT
3515 : //
3516 0 : StyleUserSelect selectStyle = StyleUserSelect::Auto;
3517 0 : nsIFrame* frame = const_cast<nsIFrame*>(this);
3518 0 : bool containsEditable = false;
3519 :
3520 0 : while (frame) {
3521 0 : const nsStyleUIReset* userinterface = frame->StyleUIReset();
3522 0 : switch (userinterface->mUserSelect) {
3523 : case StyleUserSelect::All:
3524 : case StyleUserSelect::MozAll:
3525 : {
3526 : // override the previous values
3527 0 : if (selectStyle != StyleUserSelect::MozText) {
3528 0 : selectStyle = userinterface->mUserSelect;
3529 : }
3530 0 : nsIContent* frameContent = frame->GetContent();
3531 0 : containsEditable = frameContent &&
3532 0 : frameContent->EditableDescendantCount() > 0;
3533 0 : break;
3534 : }
3535 : default:
3536 : // otherwise return the first value which is not 'auto'
3537 0 : if (selectStyle == StyleUserSelect::Auto) {
3538 0 : selectStyle = userinterface->mUserSelect;
3539 : }
3540 0 : break;
3541 : }
3542 0 : frame = nsLayoutUtils::GetParentOrPlaceholderFor(frame);
3543 : }
3544 :
3545 : // convert internal values to standard values
3546 0 : if (selectStyle == StyleUserSelect::Auto ||
3547 : selectStyle == StyleUserSelect::MozText) {
3548 0 : selectStyle = StyleUserSelect::Text;
3549 0 : } else if (selectStyle == StyleUserSelect::MozAll) {
3550 0 : selectStyle = StyleUserSelect::All;
3551 : }
3552 :
3553 : // If user tries to select all of a non-editable content,
3554 : // prevent selection if it contains editable content.
3555 0 : bool allowSelection = true;
3556 0 : if (selectStyle == StyleUserSelect::All) {
3557 0 : allowSelection = !containsEditable;
3558 : }
3559 :
3560 : // return stuff
3561 0 : if (aSelectStyle) {
3562 0 : *aSelectStyle = selectStyle;
3563 : }
3564 :
3565 0 : return !(mState & NS_FRAME_GENERATED_CONTENT) &&
3566 0 : allowSelection &&
3567 0 : selectStyle != StyleUserSelect::None;
3568 : }
3569 :
3570 : /**
3571 : * Handles the Mouse Press Event for the frame
3572 : */
3573 : NS_IMETHODIMP
3574 0 : nsFrame::HandlePress(nsPresContext* aPresContext,
3575 : WidgetGUIEvent* aEvent,
3576 : nsEventStatus* aEventStatus)
3577 : {
3578 0 : NS_ENSURE_ARG_POINTER(aEventStatus);
3579 0 : if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
3580 0 : return NS_OK;
3581 : }
3582 :
3583 0 : NS_ENSURE_ARG_POINTER(aEvent);
3584 0 : if (aEvent->mClass == eTouchEventClass) {
3585 0 : return NS_OK;
3586 : }
3587 :
3588 : //We often get out of sync state issues with mousedown events that
3589 : //get interrupted by alerts/dialogs.
3590 : //Check with the ESM to see if we should process this one
3591 0 : if (!aPresContext->EventStateManager()->EventStatusOK(aEvent))
3592 0 : return NS_OK;
3593 :
3594 0 : nsIPresShell *shell = aPresContext->GetPresShell();
3595 0 : if (!shell)
3596 0 : return NS_ERROR_FAILURE;
3597 :
3598 : // if we are in Navigator and the click is in a draggable node, we don't want
3599 : // to start selection because we don't want to interfere with a potential
3600 : // drag of said node and steal all its glory.
3601 0 : int16_t isEditor = shell->GetSelectionFlags();
3602 : //weaaak. only the editor can display frame selection not just text and images
3603 0 : isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
3604 :
3605 0 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
3606 :
3607 0 : if (!mouseEvent->IsAlt()) {
3608 0 : for (nsIContent* content = mContent; content;
3609 0 : content = content->GetParent()) {
3610 0 : if (nsContentUtils::ContentIsDraggable(content) &&
3611 0 : !content->IsEditable()) {
3612 : // coordinate stuff is the fix for bug #55921
3613 0 : if ((mRect - GetPosition()).Contains(
3614 0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this))) {
3615 0 : return NS_OK;
3616 : }
3617 : }
3618 : }
3619 : }
3620 :
3621 : // check whether style allows selection
3622 : // if not, don't tell selection the mouse event even occurred.
3623 : StyleUserSelect selectStyle;
3624 : // check for select: none
3625 0 : if (!IsSelectable(&selectStyle)) {
3626 0 : return NS_OK;
3627 : }
3628 :
3629 : // When implementing StyleUserSelect::Element, StyleUserSelect::Elements and
3630 : // StyleUserSelect::Toggle, need to change this logic
3631 0 : bool useFrameSelection = (selectStyle == StyleUserSelect::Text);
3632 :
3633 : // If the mouse is dragged outside the nearest enclosing scrollable area
3634 : // while making a selection, the area will be scrolled. To do this, capture
3635 : // the mouse on the nearest scrollable frame. If there isn't a scrollable
3636 : // frame, or something else is already capturing the mouse, there's no
3637 : // reason to capture.
3638 0 : bool hasCapturedContent = false;
3639 0 : if (!nsIPresShell::GetCapturingContent()) {
3640 : nsIScrollableFrame* scrollFrame =
3641 0 : nsLayoutUtils::GetNearestScrollableFrame(this,
3642 : nsLayoutUtils::SCROLLABLE_SAME_DOC |
3643 0 : nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
3644 0 : if (scrollFrame) {
3645 0 : nsIFrame* capturingFrame = do_QueryFrame(scrollFrame);
3646 0 : nsIPresShell::SetCapturingContent(capturingFrame->GetContent(),
3647 0 : CAPTURE_IGNOREALLOWED);
3648 0 : hasCapturedContent = true;
3649 : }
3650 : }
3651 :
3652 : // XXX This is screwy; it really should use the selection frame, not the
3653 : // event frame
3654 0 : const nsFrameSelection* frameselection = nullptr;
3655 0 : if (useFrameSelection)
3656 0 : frameselection = GetConstFrameSelection();
3657 : else
3658 0 : frameselection = shell->ConstFrameSelection();
3659 :
3660 0 : if (!frameselection || frameselection->GetDisplaySelection() == nsISelectionController::SELECTION_OFF)
3661 0 : return NS_OK;//nothing to do we cannot affect selection from here
3662 :
3663 : #ifdef XP_MACOSX
3664 : if (mouseEvent->IsControl())
3665 : return NS_OK;//short circuit. hard coded for mac due to time restraints.
3666 : bool control = mouseEvent->IsMeta();
3667 : #else
3668 0 : bool control = mouseEvent->IsControl();
3669 : #endif
3670 :
3671 0 : RefPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection);
3672 0 : if (mouseEvent->mClickCount > 1) {
3673 : // These methods aren't const but can't actually delete anything,
3674 : // so no need for AutoWeakFrame.
3675 0 : fc->SetDragState(true);
3676 0 : fc->SetMouseDoubleDown(true);
3677 0 : return HandleMultiplePress(aPresContext, mouseEvent, aEventStatus, control);
3678 : }
3679 :
3680 0 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
3681 0 : ContentOffsets offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
3682 :
3683 0 : if (!offsets.content)
3684 0 : return NS_ERROR_FAILURE;
3685 :
3686 : // On touchables devices, touch the screen is usually a pan action,
3687 : // so let's reposition the caret if needed but do not select text
3688 : // if the touch did not happen over an editable element. Otherwise,
3689 : // let the user move the caret by tapping and dragging.
3690 0 : if (!offsets.content->IsEditable() &&
3691 0 : Preferences::GetBool("browser.ignoreNativeFrameTextSelection", false)) {
3692 : // On touchables devices, mouse events are generated if the gesture is a tap.
3693 : // Such events are never going to generate a drag action, so let's release
3694 : // captured content if any.
3695 0 : if (hasCapturedContent) {
3696 0 : nsIPresShell::SetCapturingContent(nullptr, 0);
3697 : }
3698 :
3699 0 : return fc->HandleClick(offsets.content, offsets.StartOffset(),
3700 0 : offsets.EndOffset(), false, false,
3701 0 : offsets.associate);
3702 : }
3703 :
3704 : // Let Ctrl/Cmd+mouse down do table selection instead of drag initiation
3705 0 : nsCOMPtr<nsIContent>parentContent;
3706 : int32_t contentOffset;
3707 : int32_t target;
3708 : nsresult rv;
3709 0 : rv = GetDataForTableSelection(frameselection, shell, mouseEvent,
3710 0 : getter_AddRefs(parentContent), &contentOffset,
3711 0 : &target);
3712 0 : if (NS_SUCCEEDED(rv) && parentContent)
3713 : {
3714 0 : fc->SetDragState(true);
3715 0 : return fc->HandleTableSelection(parentContent, contentOffset, target,
3716 0 : mouseEvent);
3717 : }
3718 :
3719 0 : fc->SetDelayedCaretData(0);
3720 :
3721 : // Check if any part of this frame is selected, and if the
3722 : // user clicked inside the selected region. If so, we delay
3723 : // starting a new selection since the user may be trying to
3724 : // drag the selected region to some other app.
3725 :
3726 0 : if (GetContent()->IsSelectionDescendant())
3727 : {
3728 0 : bool inSelection = false;
3729 : UniquePtr<SelectionDetails> details
3730 : = frameselection->LookUpSelection(offsets.content, 0,
3731 0 : offsets.EndOffset(), false);
3732 :
3733 : //
3734 : // If there are any details, check to see if the user clicked
3735 : // within any selected region of the frame.
3736 : //
3737 :
3738 0 : for (SelectionDetails* curDetail = details.get();
3739 0 : curDetail;
3740 0 : curDetail = curDetail->mNext.get()) {
3741 : //
3742 : // If the user clicked inside a selection, then just
3743 : // return without doing anything. We will handle placing
3744 : // the caret later on when the mouse is released. We ignore
3745 : // the spellcheck, find and url formatting selections.
3746 : //
3747 0 : if (curDetail->mSelectionType != SelectionType::eSpellCheck &&
3748 0 : curDetail->mSelectionType != SelectionType::eFind &&
3749 0 : curDetail->mSelectionType != SelectionType::eURLSecondary &&
3750 0 : curDetail->mSelectionType != SelectionType::eURLStrikeout &&
3751 0 : curDetail->mStart <= offsets.StartOffset() &&
3752 0 : offsets.EndOffset() <= curDetail->mEnd)
3753 : {
3754 0 : inSelection = true;
3755 : }
3756 : }
3757 :
3758 0 : if (inSelection) {
3759 0 : fc->SetDragState(false);
3760 0 : fc->SetDelayedCaretData(mouseEvent);
3761 0 : return NS_OK;
3762 : }
3763 : }
3764 :
3765 0 : fc->SetDragState(true);
3766 :
3767 : // Do not touch any nsFrame members after this point without adding
3768 : // weakFrame checks.
3769 0 : rv = fc->HandleClick(offsets.content, offsets.StartOffset(),
3770 0 : offsets.EndOffset(), mouseEvent->IsShift(), control,
3771 0 : offsets.associate);
3772 :
3773 0 : if (NS_FAILED(rv))
3774 0 : return rv;
3775 :
3776 0 : if (offsets.offset != offsets.secondaryOffset)
3777 0 : fc->MaintainSelection();
3778 :
3779 0 : if (isEditor && !mouseEvent->IsShift() &&
3780 0 : (offsets.EndOffset() - offsets.StartOffset()) == 1)
3781 : {
3782 : // A single node is selected and we aren't extending an existing
3783 : // selection, which means the user clicked directly on an object (either
3784 : // -moz-user-select: all or a non-text node without children).
3785 : // Therefore, disable selection extension during mouse moves.
3786 : // XXX This is a bit hacky; shouldn't editor be able to deal with this?
3787 0 : fc->SetDragState(false);
3788 : }
3789 :
3790 0 : return rv;
3791 : }
3792 :
3793 : /*
3794 : * SelectByTypeAtPoint
3795 : *
3796 : * Search for selectable content at point and attempt to select
3797 : * based on the start and end selection behaviours.
3798 : *
3799 : * @param aPresContext Presentation context
3800 : * @param aPoint Point at which selection will occur. Coordinates
3801 : * should be relaitve to this frame.
3802 : * @param aBeginAmountType, aEndAmountType Selection behavior, see
3803 : * nsIFrame for definitions.
3804 : * @param aSelectFlags Selection flags defined in nsFame.h.
3805 : * @return success or failure at finding suitable content to select.
3806 : */
3807 : nsresult
3808 0 : nsFrame::SelectByTypeAtPoint(nsPresContext* aPresContext,
3809 : const nsPoint& aPoint,
3810 : nsSelectionAmount aBeginAmountType,
3811 : nsSelectionAmount aEndAmountType,
3812 : uint32_t aSelectFlags)
3813 : {
3814 0 : NS_ENSURE_ARG_POINTER(aPresContext);
3815 :
3816 : // No point in selecting if selection is turned off
3817 0 : if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF)
3818 0 : return NS_OK;
3819 :
3820 0 : ContentOffsets offsets = GetContentOffsetsFromPoint(aPoint, SKIP_HIDDEN);
3821 0 : if (!offsets.content)
3822 0 : return NS_ERROR_FAILURE;
3823 :
3824 : int32_t offset;
3825 : const nsFrameSelection* frameSelection =
3826 0 : PresContext()->GetPresShell()->ConstFrameSelection();
3827 : nsIFrame* theFrame = frameSelection->
3828 0 : GetFrameForNodeOffset(offsets.content, offsets.offset,
3829 0 : offsets.associate, &offset);
3830 0 : if (!theFrame)
3831 0 : return NS_ERROR_FAILURE;
3832 :
3833 0 : nsFrame* frame = static_cast<nsFrame*>(theFrame);
3834 0 : return frame->PeekBackwardAndForward(aBeginAmountType, aEndAmountType, offset,
3835 : aBeginAmountType != eSelectWord,
3836 0 : aSelectFlags);
3837 : }
3838 :
3839 : /**
3840 : * Multiple Mouse Press -- line or paragraph selection -- for the frame.
3841 : * Wouldn't it be nice if this didn't have to be hardwired into Frame code?
3842 : */
3843 : NS_IMETHODIMP
3844 0 : nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
3845 : WidgetGUIEvent* aEvent,
3846 : nsEventStatus* aEventStatus,
3847 : bool aControlHeld)
3848 : {
3849 0 : NS_ENSURE_ARG_POINTER(aEvent);
3850 0 : NS_ENSURE_ARG_POINTER(aEventStatus);
3851 :
3852 0 : if (nsEventStatus_eConsumeNoDefault == *aEventStatus ||
3853 0 : DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
3854 0 : return NS_OK;
3855 : }
3856 :
3857 : // Find out whether we're doing line or paragraph selection.
3858 : // If browser.triple_click_selects_paragraph is true, triple-click selects paragraph.
3859 : // Otherwise, triple-click selects line, and quadruple-click selects paragraph
3860 : // (on platforms that support quadruple-click).
3861 : nsSelectionAmount beginAmount, endAmount;
3862 0 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
3863 0 : if (!mouseEvent) {
3864 0 : return NS_OK;
3865 : }
3866 :
3867 0 : if (mouseEvent->mClickCount == 4) {
3868 0 : beginAmount = endAmount = eSelectParagraph;
3869 0 : } else if (mouseEvent->mClickCount == 3) {
3870 0 : if (Preferences::GetBool("browser.triple_click_selects_paragraph")) {
3871 0 : beginAmount = endAmount = eSelectParagraph;
3872 : } else {
3873 0 : beginAmount = eSelectBeginLine;
3874 0 : endAmount = eSelectEndLine;
3875 : }
3876 0 : } else if (mouseEvent->mClickCount == 2) {
3877 : // We only want inline frames; PeekBackwardAndForward dislikes blocks
3878 0 : beginAmount = endAmount = eSelectWord;
3879 : } else {
3880 0 : return NS_OK;
3881 : }
3882 :
3883 : nsPoint relPoint =
3884 0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
3885 0 : return SelectByTypeAtPoint(aPresContext, relPoint, beginAmount, endAmount,
3886 0 : (aControlHeld ? SELECT_ACCUMULATE : 0));
3887 : }
3888 :
3889 : nsresult
3890 0 : nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
3891 : nsSelectionAmount aAmountForward,
3892 : int32_t aStartPos,
3893 : bool aJumpLines,
3894 : uint32_t aSelectFlags)
3895 : {
3896 0 : nsIFrame* baseFrame = this;
3897 0 : int32_t baseOffset = aStartPos;
3898 : nsresult rv;
3899 :
3900 0 : if (aAmountBack == eSelectWord) {
3901 : // To avoid selecting the previous word when at start of word,
3902 : // first move one character forward.
3903 : nsPeekOffsetStruct pos(eSelectCharacter,
3904 : eDirNext,
3905 : aStartPos,
3906 0 : nsPoint(0, 0),
3907 : aJumpLines,
3908 : true, //limit on scrolled views
3909 : false,
3910 : false,
3911 0 : false);
3912 0 : rv = PeekOffset(&pos);
3913 0 : if (NS_SUCCEEDED(rv)) {
3914 0 : baseFrame = pos.mResultFrame;
3915 0 : baseOffset = pos.mContentOffset;
3916 : }
3917 : }
3918 :
3919 : // Use peek offset one way then the other:
3920 : nsPeekOffsetStruct startpos(aAmountBack,
3921 : eDirPrevious,
3922 : baseOffset,
3923 0 : nsPoint(0, 0),
3924 : aJumpLines,
3925 : true, //limit on scrolled views
3926 : false,
3927 : false,
3928 0 : false);
3929 0 : rv = baseFrame->PeekOffset(&startpos);
3930 0 : if (NS_FAILED(rv))
3931 0 : return rv;
3932 :
3933 : nsPeekOffsetStruct endpos(aAmountForward,
3934 : eDirNext,
3935 : aStartPos,
3936 0 : nsPoint(0, 0),
3937 : aJumpLines,
3938 : true, //limit on scrolled views
3939 : false,
3940 : false,
3941 0 : false);
3942 0 : rv = PeekOffset(&endpos);
3943 0 : if (NS_FAILED(rv))
3944 0 : return rv;
3945 :
3946 : // Keep frameSelection alive.
3947 0 : RefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
3948 :
3949 0 : rv = frameSelection->HandleClick(startpos.mResultContent,
3950 0 : startpos.mContentOffset, startpos.mContentOffset,
3951 0 : false, (aSelectFlags & SELECT_ACCUMULATE),
3952 0 : CARET_ASSOCIATE_AFTER);
3953 0 : if (NS_FAILED(rv))
3954 0 : return rv;
3955 :
3956 0 : rv = frameSelection->HandleClick(endpos.mResultContent,
3957 0 : endpos.mContentOffset, endpos.mContentOffset,
3958 : true, false,
3959 0 : CARET_ASSOCIATE_BEFORE);
3960 0 : if (NS_FAILED(rv))
3961 0 : return rv;
3962 :
3963 : // maintain selection
3964 0 : return frameSelection->MaintainSelection(aAmountBack);
3965 : }
3966 :
3967 4 : NS_IMETHODIMP nsFrame::HandleDrag(nsPresContext* aPresContext,
3968 : WidgetGUIEvent* aEvent,
3969 : nsEventStatus* aEventStatus)
3970 : {
3971 4 : MOZ_ASSERT(aEvent->mClass == eMouseEventClass,
3972 : "HandleDrag can only handle mouse event");
3973 :
3974 8 : RefPtr<nsFrameSelection> frameselection = GetFrameSelection();
3975 4 : bool mouseDown = frameselection->GetDragState();
3976 4 : if (!mouseDown) {
3977 4 : return NS_OK;
3978 : }
3979 :
3980 : nsIFrame* scrollbar =
3981 0 : nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::Scrollbar);
3982 0 : if (!scrollbar) {
3983 : // XXX Do we really need to exclude non-selectable content here?
3984 : // GetContentOffsetsFromPoint can handle it just fine, although some
3985 : // other stuff might not like it.
3986 : // NOTE: DisplaySelection() returns SELECTION_OFF for non-selectable frames.
3987 0 : if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
3988 0 : return NS_OK;
3989 : }
3990 : }
3991 :
3992 0 : frameselection->StopAutoScrollTimer();
3993 :
3994 : // Check if we are dragging in a table cell
3995 0 : nsCOMPtr<nsIContent> parentContent;
3996 : int32_t contentOffset;
3997 : int32_t target;
3998 0 : WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
3999 0 : nsCOMPtr<nsIPresShell> presShell = aPresContext->PresShell();
4000 : nsresult result;
4001 0 : result = GetDataForTableSelection(frameselection, presShell, mouseEvent,
4002 0 : getter_AddRefs(parentContent),
4003 0 : &contentOffset, &target);
4004 :
4005 0 : AutoWeakFrame weakThis = this;
4006 0 : if (NS_SUCCEEDED(result) && parentContent) {
4007 0 : frameselection->HandleTableSelection(parentContent, contentOffset, target,
4008 0 : mouseEvent);
4009 : } else {
4010 0 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent, this);
4011 0 : frameselection->HandleDrag(this, pt);
4012 : }
4013 :
4014 : // The frameselection object notifies selection listeners synchronously above
4015 : // which might have killed us.
4016 0 : if (!weakThis.IsAlive()) {
4017 0 : return NS_OK;
4018 : }
4019 :
4020 : // get the nearest scrollframe
4021 : nsIScrollableFrame* scrollFrame =
4022 0 : nsLayoutUtils::GetNearestScrollableFrame(this,
4023 : nsLayoutUtils::SCROLLABLE_SAME_DOC |
4024 0 : nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4025 :
4026 0 : if (scrollFrame) {
4027 0 : nsIFrame* capturingFrame = scrollFrame->GetScrolledFrame();
4028 0 : if (capturingFrame) {
4029 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(mouseEvent,
4030 0 : capturingFrame);
4031 0 : frameselection->StartAutoScrollTimer(capturingFrame, pt, 30);
4032 : }
4033 : }
4034 :
4035 0 : return NS_OK;
4036 : }
4037 :
4038 : /**
4039 : * This static method handles part of the nsFrame::HandleRelease in a way
4040 : * which doesn't rely on the nsFrame object to stay alive.
4041 : */
4042 : static nsresult
4043 0 : HandleFrameSelection(nsFrameSelection* aFrameSelection,
4044 : nsIFrame::ContentOffsets& aOffsets,
4045 : bool aHandleTableSel,
4046 : int32_t aContentOffsetForTableSel,
4047 : int32_t aTargetForTableSel,
4048 : nsIContent* aParentContentForTableSel,
4049 : WidgetGUIEvent* aEvent,
4050 : nsEventStatus* aEventStatus)
4051 : {
4052 0 : if (!aFrameSelection) {
4053 0 : return NS_OK;
4054 : }
4055 :
4056 0 : nsresult rv = NS_OK;
4057 :
4058 0 : if (nsEventStatus_eConsumeNoDefault != *aEventStatus) {
4059 0 : if (!aHandleTableSel) {
4060 0 : if (!aOffsets.content || !aFrameSelection->HasDelayedCaretData()) {
4061 0 : return NS_ERROR_FAILURE;
4062 : }
4063 :
4064 : // We are doing this to simulate what we would have done on HandlePress.
4065 : // We didn't do it there to give the user an opportunity to drag
4066 : // the text, but since they didn't drag, we want to place the
4067 : // caret.
4068 : // However, we'll use the mouse position from the release, since:
4069 : // * it's easier
4070 : // * that's the normal click position to use (although really, in
4071 : // the normal case, small movements that don't count as a drag
4072 : // can do selection)
4073 0 : aFrameSelection->SetDragState(true);
4074 :
4075 0 : rv = aFrameSelection->HandleClick(aOffsets.content,
4076 0 : aOffsets.StartOffset(),
4077 0 : aOffsets.EndOffset(),
4078 0 : aFrameSelection->IsShiftDownInDelayedCaretData(),
4079 : false,
4080 0 : aOffsets.associate);
4081 0 : if (NS_FAILED(rv)) {
4082 0 : return rv;
4083 : }
4084 0 : } else if (aParentContentForTableSel) {
4085 0 : aFrameSelection->SetDragState(false);
4086 0 : rv = aFrameSelection->HandleTableSelection(
4087 : aParentContentForTableSel,
4088 : aContentOffsetForTableSel,
4089 : aTargetForTableSel,
4090 0 : aEvent->AsMouseEvent());
4091 0 : if (NS_FAILED(rv)) {
4092 0 : return rv;
4093 : }
4094 : }
4095 0 : aFrameSelection->SetDelayedCaretData(0);
4096 : }
4097 :
4098 0 : aFrameSelection->SetDragState(false);
4099 0 : aFrameSelection->StopAutoScrollTimer();
4100 :
4101 0 : return NS_OK;
4102 : }
4103 :
4104 0 : NS_IMETHODIMP nsFrame::HandleRelease(nsPresContext* aPresContext,
4105 : WidgetGUIEvent* aEvent,
4106 : nsEventStatus* aEventStatus)
4107 : {
4108 0 : if (aEvent->mClass != eMouseEventClass) {
4109 0 : return NS_OK;
4110 : }
4111 :
4112 0 : nsIFrame* activeFrame = GetActiveSelectionFrame(aPresContext, this);
4113 :
4114 0 : nsCOMPtr<nsIContent> captureContent = nsIPresShell::GetCapturingContent();
4115 :
4116 : // We can unconditionally stop capturing because
4117 : // we should never be capturing when the mouse button is up
4118 0 : nsIPresShell::SetCapturingContent(nullptr, 0);
4119 :
4120 : bool selectionOff =
4121 0 : (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF);
4122 :
4123 0 : RefPtr<nsFrameSelection> frameselection;
4124 0 : ContentOffsets offsets;
4125 0 : nsCOMPtr<nsIContent> parentContent;
4126 0 : int32_t contentOffsetForTableSel = 0;
4127 0 : int32_t targetForTableSel = 0;
4128 0 : bool handleTableSelection = true;
4129 :
4130 0 : if (!selectionOff) {
4131 0 : frameselection = GetFrameSelection();
4132 0 : if (nsEventStatus_eConsumeNoDefault != *aEventStatus && frameselection) {
4133 : // Check if the frameselection recorded the mouse going down.
4134 : // If not, the user must have clicked in a part of the selection.
4135 : // Place the caret before continuing!
4136 :
4137 0 : if (frameselection->MouseDownRecorded()) {
4138 0 : nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
4139 0 : offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
4140 0 : handleTableSelection = false;
4141 : } else {
4142 0 : GetDataForTableSelection(frameselection, PresContext()->PresShell(),
4143 0 : aEvent->AsMouseEvent(),
4144 0 : getter_AddRefs(parentContent),
4145 : &contentOffsetForTableSel,
4146 0 : &targetForTableSel);
4147 : }
4148 : }
4149 : }
4150 :
4151 : // We might be capturing in some other document and the event just happened to
4152 : // trickle down here. Make sure that document's frame selection is notified.
4153 : // Note, this may cause the current nsFrame object to be deleted, bug 336592.
4154 0 : RefPtr<nsFrameSelection> frameSelection;
4155 0 : if (activeFrame != this &&
4156 0 : static_cast<nsFrame*>(activeFrame)->DisplaySelection(activeFrame->PresContext())
4157 : != nsISelectionController::SELECTION_OFF) {
4158 0 : frameSelection = activeFrame->GetFrameSelection();
4159 : }
4160 :
4161 : // Also check the selection of the capturing content which might be in a
4162 : // different document.
4163 0 : if (!frameSelection && captureContent) {
4164 0 : nsIDocument* doc = captureContent->GetUncomposedDoc();
4165 0 : if (doc) {
4166 0 : nsIPresShell* capturingShell = doc->GetShell();
4167 0 : if (capturingShell && capturingShell != PresContext()->GetPresShell()) {
4168 0 : frameSelection = capturingShell->FrameSelection();
4169 : }
4170 : }
4171 : }
4172 :
4173 0 : if (frameSelection) {
4174 0 : frameSelection->SetDragState(false);
4175 0 : frameSelection->StopAutoScrollTimer();
4176 : nsIScrollableFrame* scrollFrame =
4177 0 : nsLayoutUtils::GetNearestScrollableFrame(this,
4178 : nsLayoutUtils::SCROLLABLE_SAME_DOC |
4179 0 : nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
4180 0 : if (scrollFrame) {
4181 : // Perform any additional scrolling needed to maintain CSS snap point
4182 : // requirements when autoscrolling is over.
4183 0 : scrollFrame->ScrollSnap();
4184 : }
4185 : }
4186 :
4187 : // Do not call any methods of the current object after this point!!!
4188 : // The object is perhaps dead!
4189 :
4190 : return selectionOff
4191 0 : ? NS_OK
4192 0 : : HandleFrameSelection(frameselection, offsets, handleTableSelection,
4193 : contentOffsetForTableSel, targetForTableSel,
4194 0 : parentContent, aEvent, aEventStatus);
4195 : }
4196 :
4197 0 : struct MOZ_STACK_CLASS FrameContentRange {
4198 0 : FrameContentRange(nsIContent* aContent, int32_t aStart, int32_t aEnd) :
4199 0 : content(aContent), start(aStart), end(aEnd) { }
4200 : nsCOMPtr<nsIContent> content;
4201 : int32_t start;
4202 : int32_t end;
4203 : };
4204 :
4205 : // Retrieve the content offsets of a frame
4206 0 : static FrameContentRange GetRangeForFrame(nsIFrame* aFrame) {
4207 0 : nsCOMPtr<nsIContent> content, parent;
4208 0 : content = aFrame->GetContent();
4209 0 : if (!content) {
4210 0 : NS_WARNING("Frame has no content");
4211 0 : return FrameContentRange(nullptr, -1, -1);
4212 : }
4213 0 : LayoutFrameType type = aFrame->Type();
4214 0 : if (type == LayoutFrameType::Text) {
4215 : int32_t offset, offsetEnd;
4216 0 : aFrame->GetOffsets(offset, offsetEnd);
4217 0 : return FrameContentRange(content, offset, offsetEnd);
4218 : }
4219 0 : if (type == LayoutFrameType::Br) {
4220 0 : parent = content->GetParent();
4221 0 : int32_t beginOffset = parent->IndexOf(content);
4222 0 : return FrameContentRange(parent, beginOffset, beginOffset);
4223 : }
4224 : // Loop to deal with anonymous content, which has no index; this loop
4225 : // probably won't run more than twice under normal conditions
4226 0 : do {
4227 0 : parent = content->GetParent();
4228 0 : if (parent) {
4229 0 : int32_t beginOffset = parent->IndexOf(content);
4230 0 : if (beginOffset >= 0)
4231 0 : return FrameContentRange(parent, beginOffset, beginOffset + 1);
4232 0 : content = parent;
4233 : }
4234 : } while (parent);
4235 :
4236 : // The root content node must act differently
4237 0 : return FrameContentRange(content, 0, content->GetChildCount());
4238 : }
4239 :
4240 : // The FrameTarget represents the closest frame to a point that can be selected
4241 : // The frame is the frame represented, frameEdge says whether one end of the
4242 : // frame is the result (in which case different handling is needed), and
4243 : // afterFrame says which end is repersented if frameEdge is true
4244 : struct FrameTarget {
4245 0 : FrameTarget(nsIFrame* aFrame, bool aFrameEdge, bool aAfterFrame,
4246 0 : bool aEmptyBlock = false) :
4247 : frame(aFrame), frameEdge(aFrameEdge), afterFrame(aAfterFrame),
4248 0 : emptyBlock(aEmptyBlock) { }
4249 0 : static FrameTarget Null() {
4250 0 : return FrameTarget(nullptr, false, false);
4251 : }
4252 0 : bool IsNull() {
4253 0 : return !frame;
4254 : }
4255 : nsIFrame* frame;
4256 : bool frameEdge;
4257 : bool afterFrame;
4258 : bool emptyBlock;
4259 : };
4260 :
4261 : // See function implementation for information
4262 : static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint,
4263 : uint32_t aFlags);
4264 :
4265 0 : static bool SelfIsSelectable(nsIFrame* aFrame, uint32_t aFlags)
4266 : {
4267 0 : if ((aFlags & nsIFrame::SKIP_HIDDEN) &&
4268 0 : !aFrame->StyleVisibility()->IsVisible()) {
4269 0 : return false;
4270 : }
4271 0 : return !aFrame->IsGeneratedContentFrame() &&
4272 0 : aFrame->StyleUIReset()->mUserSelect != StyleUserSelect::None;
4273 : }
4274 :
4275 0 : static bool SelectionDescendToKids(nsIFrame* aFrame) {
4276 0 : StyleUserSelect style = aFrame->StyleUIReset()->mUserSelect;
4277 0 : nsIFrame* parent = aFrame->GetParent();
4278 : // If we are only near (not directly over) then don't traverse
4279 : // frames with independent selection (e.g. text and list controls)
4280 : // unless we're already inside such a frame (see bug 268497). Note that this
4281 : // prevents any of the users of this method from entering form controls.
4282 : // XXX We might want some way to allow using the up-arrow to go into a form
4283 : // control, but the focus didn't work right anyway; it'd probably be enough
4284 : // if the left and right arrows could enter textboxes (which I don't believe
4285 : // they can at the moment)
4286 0 : return !aFrame->IsGeneratedContentFrame() &&
4287 0 : style != StyleUserSelect::All &&
4288 0 : style != StyleUserSelect::None &&
4289 0 : ((parent->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION) ||
4290 0 : !(aFrame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION));
4291 : }
4292 :
4293 0 : static FrameTarget GetSelectionClosestFrameForChild(nsIFrame* aChild,
4294 : nsPoint aPoint,
4295 : uint32_t aFlags)
4296 : {
4297 0 : nsIFrame* parent = aChild->GetParent();
4298 0 : if (SelectionDescendToKids(aChild)) {
4299 0 : nsPoint pt = aPoint - aChild->GetOffsetTo(parent);
4300 0 : return GetSelectionClosestFrame(aChild, pt, aFlags);
4301 : }
4302 0 : return FrameTarget(aChild, false, false);
4303 : }
4304 :
4305 : // When the cursor needs to be at the beginning of a block, it shouldn't be
4306 : // before the first child. A click on a block whose first child is a block
4307 : // should put the cursor in the child. The cursor shouldn't be between the
4308 : // blocks, because that's not where it's expected.
4309 : // Note that this method is guaranteed to succeed.
4310 0 : static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame,
4311 : bool aEndFrame, uint32_t aFlags) {
4312 0 : if (SelectionDescendToKids(aFrame)) {
4313 0 : nsIFrame* result = nullptr;
4314 0 : nsIFrame *frame = aFrame->PrincipalChildList().FirstChild();
4315 0 : if (!aEndFrame) {
4316 0 : while (frame && (!SelfIsSelectable(frame, aFlags) ||
4317 0 : frame->IsEmpty()))
4318 0 : frame = frame->GetNextSibling();
4319 0 : if (frame)
4320 0 : result = frame;
4321 : } else {
4322 : // Because the frame tree is singly linked, to find the last frame,
4323 : // we have to iterate through all the frames
4324 : // XXX I have a feeling this could be slow for long blocks, although
4325 : // I can't find any slowdowns
4326 0 : while (frame) {
4327 0 : if (!frame->IsEmpty() && SelfIsSelectable(frame, aFlags))
4328 0 : result = frame;
4329 0 : frame = frame->GetNextSibling();
4330 : }
4331 : }
4332 0 : if (result)
4333 0 : return DrillDownToSelectionFrame(result, aEndFrame, aFlags);
4334 : }
4335 : // If the current frame has no targetable children, target the current frame
4336 0 : return FrameTarget(aFrame, true, aEndFrame);
4337 : }
4338 :
4339 : // This method finds the closest valid FrameTarget on a given line; if there is
4340 : // no valid FrameTarget on the line, it returns a null FrameTarget
4341 0 : static FrameTarget GetSelectionClosestFrameForLine(
4342 : nsBlockFrame* aParent,
4343 : nsBlockFrame::LineIterator aLine,
4344 : nsPoint aPoint,
4345 : uint32_t aFlags)
4346 : {
4347 0 : nsIFrame *frame = aLine->mFirstChild;
4348 : // Account for end of lines (any iterator from the block is valid)
4349 0 : if (aLine == aParent->LinesEnd())
4350 0 : return DrillDownToSelectionFrame(aParent, true, aFlags);
4351 0 : nsIFrame *closestFromIStart = nullptr, *closestFromIEnd = nullptr;
4352 0 : nscoord closestIStart = aLine->IStart(), closestIEnd = aLine->IEnd();
4353 0 : WritingMode wm = aLine->mWritingMode;
4354 0 : LogicalPoint pt(wm, aPoint, aLine->mContainerSize);
4355 0 : bool canSkipBr = false;
4356 0 : for (int32_t n = aLine->GetChildCount(); n;
4357 : --n, frame = frame->GetNextSibling()) {
4358 : // Skip brFrames. Can only skip if the line contains at least
4359 : // one selectable and non-empty frame before
4360 0 : if (!SelfIsSelectable(frame, aFlags) || frame->IsEmpty() ||
4361 0 : (canSkipBr && frame->IsBrFrame())) {
4362 0 : continue;
4363 : }
4364 0 : canSkipBr = true;
4365 0 : LogicalRect frameRect = LogicalRect(wm, frame->GetRect(),
4366 0 : aLine->mContainerSize);
4367 0 : if (pt.I(wm) >= frameRect.IStart(wm)) {
4368 0 : if (pt.I(wm) < frameRect.IEnd(wm)) {
4369 0 : return GetSelectionClosestFrameForChild(frame, aPoint, aFlags);
4370 : }
4371 0 : if (frameRect.IEnd(wm) >= closestIStart) {
4372 0 : closestFromIStart = frame;
4373 0 : closestIStart = frameRect.IEnd(wm);
4374 : }
4375 : } else {
4376 0 : if (frameRect.IStart(wm) <= closestIEnd) {
4377 0 : closestFromIEnd = frame;
4378 0 : closestIEnd = frameRect.IStart(wm);
4379 : }
4380 : }
4381 : }
4382 0 : if (!closestFromIStart && !closestFromIEnd) {
4383 : // We should only get here if there are no selectable frames on a line
4384 : // XXX Do we need more elaborate handling here?
4385 0 : return FrameTarget::Null();
4386 : }
4387 0 : if (closestFromIStart &&
4388 0 : (!closestFromIEnd ||
4389 0 : (abs(pt.I(wm) - closestIStart) <= abs(pt.I(wm) - closestIEnd)))) {
4390 : return GetSelectionClosestFrameForChild(closestFromIStart, aPoint,
4391 0 : aFlags);
4392 : }
4393 0 : return GetSelectionClosestFrameForChild(closestFromIEnd, aPoint, aFlags);
4394 : }
4395 :
4396 : // This method is for the special handling we do for block frames; they're
4397 : // special because they represent paragraphs and because they are organized
4398 : // into lines, which have bounds that are not stored elsewhere in the
4399 : // frame tree. Returns a null FrameTarget for frames which are not
4400 : // blocks or blocks with no lines except editable one.
4401 0 : static FrameTarget GetSelectionClosestFrameForBlock(nsIFrame* aFrame,
4402 : nsPoint aPoint,
4403 : uint32_t aFlags)
4404 : {
4405 0 : nsBlockFrame* bf = nsLayoutUtils::GetAsBlock(aFrame); // used only for QI
4406 0 : if (!bf)
4407 0 : return FrameTarget::Null();
4408 :
4409 : // This code searches for the correct line
4410 0 : nsBlockFrame::LineIterator firstLine = bf->LinesBegin();
4411 0 : nsBlockFrame::LineIterator end = bf->LinesEnd();
4412 0 : if (firstLine == end) {
4413 0 : nsIContent *blockContent = aFrame->GetContent();
4414 0 : if (blockContent) {
4415 : // Return with empty flag true.
4416 0 : return FrameTarget(aFrame, false, false, true);
4417 : }
4418 0 : return FrameTarget::Null();
4419 : }
4420 0 : nsBlockFrame::LineIterator curLine = firstLine;
4421 0 : nsBlockFrame::LineIterator closestLine = end;
4422 : // Convert aPoint into a LogicalPoint in the writing-mode of this block
4423 0 : WritingMode wm = curLine->mWritingMode;
4424 0 : LogicalPoint pt(wm, aPoint, curLine->mContainerSize);
4425 0 : while (curLine != end) {
4426 : // Check to see if our point lies within the line's block-direction bounds
4427 0 : nscoord BCoord = pt.B(wm) - curLine->BStart();
4428 0 : nscoord BSize = curLine->BSize();
4429 0 : if (BCoord >= 0 && BCoord < BSize) {
4430 0 : closestLine = curLine;
4431 0 : break; // We found the line; stop looking
4432 : }
4433 0 : if (BCoord < 0)
4434 0 : break;
4435 0 : ++curLine;
4436 : }
4437 :
4438 0 : if (closestLine == end) {
4439 0 : nsBlockFrame::LineIterator prevLine = curLine.prev();
4440 0 : nsBlockFrame::LineIterator nextLine = curLine;
4441 : // Avoid empty lines
4442 0 : while (nextLine != end && nextLine->IsEmpty())
4443 0 : ++nextLine;
4444 0 : while (prevLine != end && prevLine->IsEmpty())
4445 0 : --prevLine;
4446 :
4447 : // This hidden pref dictates whether a point above or below all lines comes
4448 : // up with a line or the beginning or end of the frame; 0 on Windows,
4449 : // 1 on other platforms by default at the writing of this code
4450 : int32_t dragOutOfFrame =
4451 0 : Preferences::GetInt("browser.drag_out_of_frame_style");
4452 :
4453 0 : if (prevLine == end) {
4454 0 : if (dragOutOfFrame == 1 || nextLine == end)
4455 0 : return DrillDownToSelectionFrame(aFrame, false, aFlags);
4456 0 : closestLine = nextLine;
4457 0 : } else if (nextLine == end) {
4458 0 : if (dragOutOfFrame == 1)
4459 0 : return DrillDownToSelectionFrame(aFrame, true, aFlags);
4460 0 : closestLine = prevLine;
4461 : } else { // Figure out which line is closer
4462 0 : if (pt.B(wm) - prevLine->BEnd() < nextLine->BStart() - pt.B(wm))
4463 0 : closestLine = prevLine;
4464 : else
4465 0 : closestLine = nextLine;
4466 : }
4467 : }
4468 :
4469 0 : do {
4470 : FrameTarget target = GetSelectionClosestFrameForLine(bf, closestLine,
4471 0 : aPoint, aFlags);
4472 0 : if (!target.IsNull())
4473 0 : return target;
4474 0 : ++closestLine;
4475 : } while (closestLine != end);
4476 : // Fall back to just targeting the last targetable place
4477 0 : return DrillDownToSelectionFrame(aFrame, true, aFlags);
4478 : }
4479 :
4480 : // GetSelectionClosestFrame is the helper function that calculates the closest
4481 : // frame to the given point.
4482 : // It doesn't completely account for offset styles, so needs to be used in
4483 : // restricted environments.
4484 : // Cannot handle overlapping frames correctly, so it should receive the output
4485 : // of GetFrameForPoint
4486 : // Guaranteed to return a valid FrameTarget
4487 0 : static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame, nsPoint aPoint,
4488 : uint32_t aFlags)
4489 : {
4490 : {
4491 : // Handle blocks; if the frame isn't a block, the method fails
4492 0 : FrameTarget target = GetSelectionClosestFrameForBlock(aFrame, aPoint, aFlags);
4493 0 : if (!target.IsNull())
4494 0 : return target;
4495 : }
4496 :
4497 0 : nsIFrame *kid = aFrame->PrincipalChildList().FirstChild();
4498 :
4499 0 : if (kid) {
4500 : // Go through all the child frames to find the closest one
4501 0 : nsIFrame::FrameWithDistance closest = { nullptr, nscoord_MAX, nscoord_MAX };
4502 0 : for (; kid; kid = kid->GetNextSibling()) {
4503 0 : if (!SelfIsSelectable(kid, aFlags) || kid->IsEmpty())
4504 0 : continue;
4505 :
4506 0 : kid->FindCloserFrameForSelection(aPoint, &closest);
4507 : }
4508 0 : if (closest.mFrame) {
4509 0 : if (nsSVGUtils::IsInSVGTextSubtree(closest.mFrame))
4510 0 : return FrameTarget(closest.mFrame, false, false);
4511 0 : return GetSelectionClosestFrameForChild(closest.mFrame, aPoint, aFlags);
4512 : }
4513 : }
4514 0 : return FrameTarget(aFrame, false, false);
4515 : }
4516 :
4517 0 : nsIFrame::ContentOffsets OffsetsForSingleFrame(nsIFrame* aFrame, nsPoint aPoint)
4518 : {
4519 0 : nsIFrame::ContentOffsets offsets;
4520 0 : FrameContentRange range = GetRangeForFrame(aFrame);
4521 0 : offsets.content = range.content;
4522 : // If there are continuations (meaning it's not one rectangle), this is the
4523 : // best this function can do
4524 0 : if (aFrame->GetNextContinuation() || aFrame->GetPrevContinuation()) {
4525 0 : offsets.offset = range.start;
4526 0 : offsets.secondaryOffset = range.end;
4527 0 : offsets.associate = CARET_ASSOCIATE_AFTER;
4528 0 : return offsets;
4529 : }
4530 :
4531 : // Figure out whether the offsets should be over, after, or before the frame
4532 0 : nsRect rect(nsPoint(0, 0), aFrame->GetSize());
4533 :
4534 0 : bool isBlock = aFrame->GetDisplay() != StyleDisplay::Inline;
4535 0 : bool isRtl = (aFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL);
4536 0 : if ((isBlock && rect.y < aPoint.y) ||
4537 0 : (!isBlock && ((isRtl && rect.x + rect.width / 2 > aPoint.x) ||
4538 0 : (!isRtl && rect.x + rect.width / 2 < aPoint.x)))) {
4539 0 : offsets.offset = range.end;
4540 0 : if (rect.Contains(aPoint))
4541 0 : offsets.secondaryOffset = range.start;
4542 : else
4543 0 : offsets.secondaryOffset = range.end;
4544 : } else {
4545 0 : offsets.offset = range.start;
4546 0 : if (rect.Contains(aPoint))
4547 0 : offsets.secondaryOffset = range.end;
4548 : else
4549 0 : offsets.secondaryOffset = range.start;
4550 : }
4551 0 : offsets.associate =
4552 0 : offsets.offset == range.start ? CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
4553 0 : return offsets;
4554 : }
4555 :
4556 0 : static nsIFrame* AdjustFrameForSelectionStyles(nsIFrame* aFrame) {
4557 0 : nsIFrame* adjustedFrame = aFrame;
4558 0 : for (nsIFrame* frame = aFrame; frame; frame = frame->GetParent())
4559 : {
4560 : // These are the conditions that make all children not able to handle
4561 : // a cursor.
4562 0 : StyleUserSelect userSelect = frame->StyleUIReset()->mUserSelect;
4563 0 : if (userSelect == StyleUserSelect::MozText) {
4564 : // If we see a -moz-text element, we shouldn't look further up the parent
4565 : // chain!
4566 0 : break;
4567 : }
4568 0 : if (userSelect == StyleUserSelect::All ||
4569 0 : frame->IsGeneratedContentFrame()) {
4570 0 : adjustedFrame = frame;
4571 : }
4572 : }
4573 0 : return adjustedFrame;
4574 : }
4575 :
4576 0 : nsIFrame::ContentOffsets nsIFrame::GetContentOffsetsFromPoint(nsPoint aPoint,
4577 : uint32_t aFlags)
4578 : {
4579 : nsIFrame *adjustedFrame;
4580 0 : if (aFlags & IGNORE_SELECTION_STYLE) {
4581 0 : adjustedFrame = this;
4582 : }
4583 : else {
4584 : // This section of code deals with special selection styles. Note that
4585 : // -moz-all exists, even though it doesn't need to be explicitly handled.
4586 : //
4587 : // The offset is forced not to end up in generated content; content offsets
4588 : // cannot represent content outside of the document's content tree.
4589 :
4590 0 : adjustedFrame = AdjustFrameForSelectionStyles(this);
4591 :
4592 : // -moz-user-select: all needs special handling, because clicking on it
4593 : // should lead to the whole frame being selected
4594 0 : if (adjustedFrame && adjustedFrame->StyleUIReset()->mUserSelect ==
4595 : StyleUserSelect::All) {
4596 0 : nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
4597 0 : return OffsetsForSingleFrame(adjustedFrame, adjustedPoint);
4598 : }
4599 :
4600 : // For other cases, try to find a closest frame starting from the parent of
4601 : // the unselectable frame
4602 0 : if (adjustedFrame != this)
4603 0 : adjustedFrame = adjustedFrame->GetParent();
4604 : }
4605 :
4606 0 : nsPoint adjustedPoint = aPoint + this->GetOffsetTo(adjustedFrame);
4607 :
4608 : FrameTarget closest =
4609 0 : GetSelectionClosestFrame(adjustedFrame, adjustedPoint, aFlags);
4610 :
4611 0 : if (closest.emptyBlock) {
4612 0 : ContentOffsets offsets;
4613 0 : NS_ASSERTION(closest.frame,
4614 : "closest.frame must not be null when it's empty");
4615 0 : offsets.content = closest.frame->GetContent();
4616 0 : offsets.offset = 0;
4617 0 : offsets.secondaryOffset = 0;
4618 0 : offsets.associate = CARET_ASSOCIATE_AFTER;
4619 0 : return offsets;
4620 : }
4621 :
4622 : // If the correct offset is at one end of a frame, use offset-based
4623 : // calculation method
4624 0 : if (closest.frameEdge) {
4625 0 : ContentOffsets offsets;
4626 0 : FrameContentRange range = GetRangeForFrame(closest.frame);
4627 0 : offsets.content = range.content;
4628 0 : if (closest.afterFrame)
4629 0 : offsets.offset = range.end;
4630 : else
4631 0 : offsets.offset = range.start;
4632 0 : offsets.secondaryOffset = offsets.offset;
4633 0 : offsets.associate = offsets.offset == range.start ?
4634 : CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
4635 0 : return offsets;
4636 : }
4637 :
4638 0 : nsPoint pt;
4639 0 : if (closest.frame != this) {
4640 0 : if (nsSVGUtils::IsInSVGTextSubtree(closest.frame)) {
4641 0 : pt = nsLayoutUtils::TransformAncestorPointToFrame(closest.frame,
4642 : aPoint, this);
4643 : } else {
4644 0 : pt = aPoint - closest.frame->GetOffsetTo(this);
4645 : }
4646 : } else {
4647 0 : pt = aPoint;
4648 : }
4649 0 : return static_cast<nsFrame*>(closest.frame)->CalcContentOffsetsFromFramePoint(pt);
4650 :
4651 : // XXX should I add some kind of offset standardization?
4652 : // consider <b>xxxxx</b><i>zzzzz</i>; should any click between the last
4653 : // x and first z put the cursor in the same logical position in addition
4654 : // to the same visual position?
4655 : }
4656 :
4657 0 : nsIFrame::ContentOffsets nsFrame::CalcContentOffsetsFromFramePoint(nsPoint aPoint)
4658 : {
4659 0 : return OffsetsForSingleFrame(this, aPoint);
4660 : }
4661 :
4662 : void
4663 3 : nsIFrame::AssociateImage(const nsStyleImage& aImage, nsPresContext* aPresContext)
4664 : {
4665 3 : if (aImage.GetType() != eStyleImageType_Image) {
4666 3 : return;
4667 : }
4668 :
4669 0 : imgRequestProxy* req = aImage.GetImageData();
4670 0 : if (!req) {
4671 0 : return;
4672 : }
4673 :
4674 : mozilla::css::ImageLoader* loader =
4675 0 : aPresContext->Document()->StyleImageLoader();
4676 :
4677 : // If this fails there's not much we can do ...
4678 0 : loader->AssociateRequestToFrame(req, this);
4679 : }
4680 :
4681 : nsresult
4682 0 : nsFrame::GetCursor(const nsPoint& aPoint,
4683 : nsIFrame::Cursor& aCursor)
4684 : {
4685 0 : FillCursorInformationFromStyle(StyleUserInterface(), aCursor);
4686 0 : if (NS_STYLE_CURSOR_AUTO == aCursor.mCursor) {
4687 : // If this is editable, I-beam cursor is better for most elements.
4688 0 : aCursor.mCursor =
4689 0 : (mContent && mContent->IsEditable())
4690 0 : ? NS_STYLE_CURSOR_TEXT : NS_STYLE_CURSOR_DEFAULT;
4691 : }
4692 0 : if (NS_STYLE_CURSOR_TEXT == aCursor.mCursor &&
4693 0 : GetWritingMode().IsVertical()) {
4694 : // Per CSS UI spec, UA may treat value 'text' as
4695 : // 'vertical-text' for vertical text.
4696 0 : aCursor.mCursor = NS_STYLE_CURSOR_VERTICAL_TEXT;
4697 : }
4698 :
4699 0 : return NS_OK;
4700 : }
4701 :
4702 : // Resize and incremental reflow
4703 :
4704 : /* virtual */ void
4705 263 : nsFrame::MarkIntrinsicISizesDirty()
4706 : {
4707 : // This version is meant only for what used to be box-to-block adaptors.
4708 : // It should not be called by other derived classes.
4709 263 : if (::IsXULBoxWrapped(this)) {
4710 90 : nsBoxLayoutMetrics *metrics = BoxMetrics();
4711 :
4712 90 : SizeNeedsRecalc(metrics->mPrefSize);
4713 90 : SizeNeedsRecalc(metrics->mMinSize);
4714 90 : SizeNeedsRecalc(metrics->mMaxSize);
4715 90 : SizeNeedsRecalc(metrics->mBlockPrefSize);
4716 90 : SizeNeedsRecalc(metrics->mBlockMinSize);
4717 90 : CoordNeedsRecalc(metrics->mFlex);
4718 90 : CoordNeedsRecalc(metrics->mAscent);
4719 : }
4720 :
4721 263 : if (GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT) {
4722 145 : nsFontInflationData::MarkFontInflationDataTextDirty(this);
4723 : }
4724 263 : }
4725 :
4726 : /* virtual */ nscoord
4727 62 : nsFrame::GetMinISize(gfxContext *aRenderingContext)
4728 : {
4729 62 : nscoord result = 0;
4730 124 : DISPLAY_MIN_WIDTH(this, result);
4731 124 : return result;
4732 : }
4733 :
4734 : /* virtual */ nscoord
4735 62 : nsFrame::GetPrefISize(gfxContext *aRenderingContext)
4736 : {
4737 62 : nscoord result = 0;
4738 124 : DISPLAY_PREF_WIDTH(this, result);
4739 124 : return result;
4740 : }
4741 :
4742 : /* virtual */ void
4743 14 : nsFrame::AddInlineMinISize(gfxContext* aRenderingContext,
4744 : nsIFrame::InlineMinISizeData* aData)
4745 : {
4746 14 : nscoord isize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
4747 14 : this, nsLayoutUtils::MIN_ISIZE);
4748 14 : aData->DefaultAddInlineMinISize(this, isize);
4749 14 : }
4750 :
4751 : /* virtual */ void
4752 11 : nsFrame::AddInlinePrefISize(gfxContext* aRenderingContext,
4753 : nsIFrame::InlinePrefISizeData* aData)
4754 : {
4755 11 : nscoord isize = nsLayoutUtils::IntrinsicForContainer(aRenderingContext,
4756 11 : this, nsLayoutUtils::PREF_ISIZE);
4757 11 : aData->DefaultAddInlinePrefISize(isize);
4758 11 : }
4759 :
4760 : void
4761 14 : nsIFrame::InlineMinISizeData::DefaultAddInlineMinISize(nsIFrame* aFrame,
4762 : nscoord aISize,
4763 : bool aAllowBreak)
4764 : {
4765 14 : auto parent = aFrame->GetParent();
4766 14 : MOZ_ASSERT(parent, "Must have a parent if we get here!");
4767 14 : const bool mayBreak = aAllowBreak &&
4768 28 : !aFrame->CanContinueTextRun() &&
4769 42 : !parent->StyleContext()->ShouldSuppressLineBreak() &&
4770 28 : parent->StyleText()->WhiteSpaceCanWrap(parent);
4771 14 : if (mayBreak) {
4772 14 : OptionallyBreak();
4773 : }
4774 14 : mTrailingWhitespace = 0;
4775 14 : mSkipWhitespace = false;
4776 14 : mCurrentLine += aISize;
4777 14 : mAtStartOfLine = false;
4778 14 : if (mayBreak) {
4779 14 : OptionallyBreak();
4780 : }
4781 14 : }
4782 :
4783 : void
4784 11 : nsIFrame::InlinePrefISizeData::DefaultAddInlinePrefISize(nscoord aISize)
4785 : {
4786 11 : mCurrentLine = NSCoordSaturatingAdd(mCurrentLine, aISize);
4787 11 : mTrailingWhitespace = 0;
4788 11 : mSkipWhitespace = false;
4789 11 : mLineIsEmpty = false;
4790 11 : }
4791 :
4792 : void
4793 51 : nsIFrame::InlineMinISizeData::ForceBreak()
4794 : {
4795 51 : mCurrentLine -= mTrailingWhitespace;
4796 51 : mPrevLines = std::max(mPrevLines, mCurrentLine);
4797 51 : mCurrentLine = mTrailingWhitespace = 0;
4798 :
4799 51 : for (uint32_t i = 0, i_end = mFloats.Length(); i != i_end; ++i) {
4800 0 : nscoord float_min = mFloats[i].Width();
4801 0 : if (float_min > mPrevLines)
4802 0 : mPrevLines = float_min;
4803 : }
4804 51 : mFloats.Clear();
4805 51 : mSkipWhitespace = true;
4806 51 : }
4807 :
4808 : void
4809 28 : nsIFrame::InlineMinISizeData::OptionallyBreak(nscoord aHyphenWidth)
4810 : {
4811 : // If we can fit more content into a smaller width by staying on this
4812 : // line (because we're still at a negative offset due to negative
4813 : // text-indent or negative margin), don't break. Otherwise, do the
4814 : // same as ForceBreak. it doesn't really matter when we accumulate
4815 : // floats.
4816 28 : if (mCurrentLine + aHyphenWidth < 0 || mAtStartOfLine)
4817 14 : return;
4818 14 : mCurrentLine += aHyphenWidth;
4819 14 : ForceBreak();
4820 : }
4821 :
4822 : void
4823 34 : nsIFrame::InlinePrefISizeData::ForceBreak(StyleClear aBreakType)
4824 : {
4825 34 : MOZ_ASSERT(aBreakType == StyleClear::None ||
4826 : aBreakType == StyleClear::Both ||
4827 : aBreakType == StyleClear::Left ||
4828 : aBreakType == StyleClear::Right,
4829 : "Must be a physical break type");
4830 :
4831 : // If this force break is not clearing any float, we can leave all the
4832 : // floats to the next force break.
4833 34 : if (mFloats.Length() != 0 && aBreakType != StyleClear::None) {
4834 : // preferred widths accumulated for floats that have already
4835 : // been cleared past
4836 0 : nscoord floats_done = 0,
4837 : // preferred widths accumulated for floats that have not yet
4838 : // been cleared past
4839 0 : floats_cur_left = 0,
4840 0 : floats_cur_right = 0;
4841 0 : const WritingMode wm = mLineContainerWM;
4842 :
4843 0 : for (uint32_t i = 0, i_end = mFloats.Length(); i != i_end; ++i) {
4844 0 : const FloatInfo& floatInfo = mFloats[i];
4845 0 : const nsStyleDisplay* floatDisp = floatInfo.Frame()->StyleDisplay();
4846 0 : StyleClear breakType = floatDisp->PhysicalBreakType(wm);
4847 0 : if (breakType == StyleClear::Left ||
4848 0 : breakType == StyleClear::Right ||
4849 : breakType == StyleClear::Both) {
4850 0 : nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left,
4851 0 : floats_cur_right);
4852 0 : if (floats_cur > floats_done) {
4853 0 : floats_done = floats_cur;
4854 : }
4855 0 : if (breakType != StyleClear::Right) {
4856 0 : floats_cur_left = 0;
4857 : }
4858 0 : if (breakType != StyleClear::Left) {
4859 0 : floats_cur_right = 0;
4860 : }
4861 : }
4862 :
4863 0 : StyleFloat floatStyle = floatDisp->PhysicalFloats(wm);
4864 : nscoord& floats_cur =
4865 0 : floatStyle == StyleFloat::Left ? floats_cur_left : floats_cur_right;
4866 0 : nscoord floatWidth = floatInfo.Width();
4867 : // Negative-width floats don't change the available space so they
4868 : // shouldn't change our intrinsic line width either.
4869 0 : floats_cur =
4870 0 : NSCoordSaturatingAdd(floats_cur, std::max(0, floatWidth));
4871 : }
4872 :
4873 : nscoord floats_cur =
4874 0 : NSCoordSaturatingAdd(floats_cur_left, floats_cur_right);
4875 0 : if (floats_cur > floats_done)
4876 0 : floats_done = floats_cur;
4877 :
4878 0 : mCurrentLine = NSCoordSaturatingAdd(mCurrentLine, floats_done);
4879 :
4880 0 : if (aBreakType == StyleClear::Both) {
4881 0 : mFloats.Clear();
4882 : } else {
4883 : // If the break type does not clear all floats, it means there may
4884 : // be some floats whose isize should contribute to the intrinsic
4885 : // isize of the next line. The code here scans the current mFloats
4886 : // and keeps floats which are not cleared by this break. Note that
4887 : // floats may be cleared directly or indirectly. See below.
4888 0 : nsTArray<FloatInfo> newFloats;
4889 0 : MOZ_ASSERT(aBreakType == StyleClear::Left ||
4890 : aBreakType == StyleClear::Right,
4891 : "Other values should have been handled in other branches");
4892 : StyleFloat clearFloatType =
4893 0 : aBreakType == StyleClear::Left ? StyleFloat::Left : StyleFloat::Right;
4894 : // Iterate the array in reverse so that we can stop when there are
4895 : // no longer any floats we need to keep. See below.
4896 0 : for (FloatInfo& floatInfo : Reversed(mFloats)) {
4897 0 : const nsStyleDisplay* floatDisp = floatInfo.Frame()->StyleDisplay();
4898 0 : if (floatDisp->PhysicalFloats(wm) != clearFloatType) {
4899 0 : newFloats.AppendElement(floatInfo);
4900 : } else {
4901 : // This is a float on the side that this break directly clears
4902 : // which means we're not keeping it in mFloats. However, if
4903 : // this float clears floats on the opposite side (via a value
4904 : // of either 'both' or one of 'left'/'right'), any remaining
4905 : // (earlier) floats on that side would be indirectly cleared
4906 : // as well. Thus, we should break out of this loop and stop
4907 : // considering earlier floats to be kept in mFloats.
4908 0 : StyleClear floatBreakType = floatDisp->PhysicalBreakType(wm);
4909 0 : if (floatBreakType != aBreakType &&
4910 : floatBreakType != StyleClear::None) {
4911 0 : break;
4912 : }
4913 : }
4914 : }
4915 0 : newFloats.Reverse();
4916 0 : mFloats = Move(newFloats);
4917 : }
4918 : }
4919 :
4920 34 : mCurrentLine =
4921 34 : NSCoordSaturatingSubtract(mCurrentLine, mTrailingWhitespace, nscoord_MAX);
4922 34 : mPrevLines = std::max(mPrevLines, mCurrentLine);
4923 34 : mCurrentLine = mTrailingWhitespace = 0;
4924 34 : mSkipWhitespace = true;
4925 34 : mLineIsEmpty = true;
4926 34 : }
4927 :
4928 : static void
4929 100 : AddCoord(const nsStyleCoord& aStyle,
4930 : nsIFrame* aFrame,
4931 : nscoord* aCoord, float* aPercent,
4932 : bool aClampNegativeToZero)
4933 : {
4934 100 : switch (aStyle.GetUnit()) {
4935 : case eStyleUnit_Coord: {
4936 100 : NS_ASSERTION(!aClampNegativeToZero || aStyle.GetCoordValue() >= 0,
4937 : "unexpected negative value");
4938 100 : *aCoord += aStyle.GetCoordValue();
4939 100 : return;
4940 : }
4941 : case eStyleUnit_Percent: {
4942 0 : NS_ASSERTION(!aClampNegativeToZero || aStyle.GetPercentValue() >= 0.0f,
4943 : "unexpected negative value");
4944 0 : *aPercent += aStyle.GetPercentValue();
4945 0 : return;
4946 : }
4947 : case eStyleUnit_Calc: {
4948 0 : const nsStyleCoord::Calc *calc = aStyle.GetCalcValue();
4949 0 : if (aClampNegativeToZero) {
4950 : // This is far from ideal when one is negative and one is positive.
4951 0 : *aCoord += std::max(calc->mLength, 0);
4952 0 : *aPercent += std::max(calc->mPercent, 0.0f);
4953 : } else {
4954 0 : *aCoord += calc->mLength;
4955 0 : *aPercent += calc->mPercent;
4956 : }
4957 0 : return;
4958 : }
4959 : default: {
4960 0 : return;
4961 : }
4962 : }
4963 : }
4964 :
4965 : static nsIFrame::IntrinsicISizeOffsetData
4966 25 : IntrinsicSizeOffsets(nsIFrame* aFrame, bool aForISize)
4967 : {
4968 25 : nsIFrame::IntrinsicISizeOffsetData result;
4969 25 : WritingMode wm = aFrame->GetWritingMode();
4970 25 : const nsStyleMargin* styleMargin = aFrame->StyleMargin();
4971 25 : bool verticalAxis = aForISize == wm.IsVertical();
4972 50 : AddCoord(verticalAxis ? styleMargin->mMargin.GetTop()
4973 : : styleMargin->mMargin.GetLeft(),
4974 : aFrame, &result.hMargin, &result.hPctMargin,
4975 25 : false);
4976 50 : AddCoord(verticalAxis ? styleMargin->mMargin.GetBottom()
4977 : : styleMargin->mMargin.GetRight(),
4978 : aFrame, &result.hMargin, &result.hPctMargin,
4979 25 : false);
4980 :
4981 25 : const nsStylePadding* stylePadding = aFrame->StylePadding();
4982 50 : AddCoord(verticalAxis ? stylePadding->mPadding.GetTop()
4983 : : stylePadding->mPadding.GetLeft(),
4984 : aFrame, &result.hPadding, &result.hPctPadding,
4985 25 : true);
4986 50 : AddCoord(verticalAxis ? stylePadding->mPadding.GetBottom()
4987 : : stylePadding->mPadding.GetRight(),
4988 : aFrame, &result.hPadding, &result.hPctPadding,
4989 25 : true);
4990 :
4991 25 : const nsStyleBorder* styleBorder = aFrame->StyleBorder();
4992 25 : if (verticalAxis) {
4993 0 : result.hBorder += styleBorder->GetComputedBorderWidth(eSideTop);
4994 0 : result.hBorder += styleBorder->GetComputedBorderWidth(eSideBottom);
4995 : } else {
4996 25 : result.hBorder += styleBorder->GetComputedBorderWidth(eSideLeft);
4997 25 : result.hBorder += styleBorder->GetComputedBorderWidth(eSideRight);
4998 : }
4999 :
5000 25 : const nsStyleDisplay* disp = aFrame->StyleDisplay();
5001 25 : if (aFrame->IsThemed(disp)) {
5002 0 : nsPresContext* presContext = aFrame->PresContext();
5003 :
5004 0 : nsIntMargin border;
5005 0 : presContext->GetTheme()->GetWidgetBorder(presContext->DeviceContext(),
5006 0 : aFrame, disp->mAppearance,
5007 0 : &border);
5008 0 : result.hBorder =
5009 0 : presContext->DevPixelsToAppUnits(verticalAxis ? border.TopBottom()
5010 : : border.LeftRight());
5011 :
5012 0 : nsIntMargin padding;
5013 0 : if (presContext->GetTheme()->GetWidgetPadding(presContext->DeviceContext(),
5014 0 : aFrame, disp->mAppearance,
5015 0 : &padding)) {
5016 0 : result.hPadding =
5017 0 : presContext->DevPixelsToAppUnits(verticalAxis ? padding.TopBottom()
5018 : : padding.LeftRight());
5019 0 : result.hPctPadding = 0;
5020 : }
5021 : }
5022 25 : return result;
5023 : }
5024 :
5025 : /* virtual */ nsIFrame::IntrinsicISizeOffsetData
5026 25 : nsFrame::IntrinsicISizeOffsets()
5027 : {
5028 25 : return IntrinsicSizeOffsets(this, true);
5029 : }
5030 :
5031 : nsIFrame::IntrinsicISizeOffsetData
5032 0 : nsIFrame::IntrinsicBSizeOffsets()
5033 : {
5034 0 : return IntrinsicSizeOffsets(this, false);
5035 : }
5036 :
5037 : /* virtual */ IntrinsicSize
5038 0 : nsFrame::GetIntrinsicSize()
5039 : {
5040 0 : return IntrinsicSize(); // default is width/height set to eStyleUnit_None
5041 : }
5042 :
5043 : /* virtual */ nsSize
5044 440 : nsFrame::GetIntrinsicRatio()
5045 : {
5046 440 : return nsSize(0, 0);
5047 : }
5048 :
5049 : /* virtual */
5050 : LogicalSize
5051 394 : nsFrame::ComputeSize(gfxContext* aRenderingContext,
5052 : WritingMode aWM,
5053 : const LogicalSize& aCBSize,
5054 : nscoord aAvailableISize,
5055 : const LogicalSize& aMargin,
5056 : const LogicalSize& aBorder,
5057 : const LogicalSize& aPadding,
5058 : ComputeSizeFlags aFlags)
5059 : {
5060 394 : MOZ_ASSERT(GetIntrinsicRatio() == nsSize(0,0),
5061 : "Please override this method and call "
5062 : "nsFrame::ComputeSizeWithIntrinsicDimensions instead.");
5063 : LogicalSize result = ComputeAutoSize(aRenderingContext, aWM,
5064 : aCBSize, aAvailableISize,
5065 : aMargin, aBorder, aPadding,
5066 394 : aFlags);
5067 394 : const nsStylePosition *stylePos = StylePosition();
5068 :
5069 394 : LogicalSize boxSizingAdjust(aWM);
5070 394 : if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
5071 100 : boxSizingAdjust = aBorder + aPadding;
5072 : }
5073 : nscoord boxSizingToMarginEdgeISize =
5074 394 : aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) -
5075 394 : boxSizingAdjust.ISize(aWM);
5076 :
5077 394 : const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM);
5078 394 : const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM);
5079 :
5080 394 : auto parentFrame = GetParent();
5081 394 : auto alignCB = parentFrame;
5082 394 : bool isGridItem = parentFrame && parentFrame->IsGridContainerFrame() &&
5083 394 : !(GetStateBits() & NS_FRAME_OUT_OF_FLOW);
5084 394 : if (parentFrame && parentFrame->IsTableWrapperFrame() && IsTableFrame()) {
5085 : // An inner table frame is sized as a grid item if its table wrapper is,
5086 : // because they actually have the same CB (the wrapper's CB).
5087 : // @see ReflowInput::InitCBReflowInput
5088 0 : auto tableWrapper = GetParent();
5089 0 : auto grandParent = tableWrapper->GetParent();
5090 0 : isGridItem = (grandParent->IsGridContainerFrame() &&
5091 0 : !(tableWrapper->GetStateBits() & NS_FRAME_OUT_OF_FLOW));
5092 0 : if (isGridItem) {
5093 : // When resolving justify/align-self below, we want to use the grid
5094 : // container's justify/align-items value and WritingMode.
5095 0 : alignCB = grandParent;
5096 : }
5097 : }
5098 394 : bool isFlexItem = parentFrame && parentFrame->IsFlexContainerFrame() &&
5099 394 : !(GetStateBits() & NS_FRAME_OUT_OF_FLOW);
5100 394 : bool isInlineFlexItem = false;
5101 394 : if (isFlexItem) {
5102 : // Flex items use their "flex-basis" property in place of their main-size
5103 : // property (e.g. "width") for sizing purposes, *unless* they have
5104 : // "flex-basis:auto", in which case they use their main-size property after
5105 : // all.
5106 0 : uint32_t flexDirection = GetParent()->StylePosition()->mFlexDirection;
5107 0 : isInlineFlexItem =
5108 0 : flexDirection == NS_STYLE_FLEX_DIRECTION_ROW ||
5109 : flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE;
5110 :
5111 : // NOTE: The logic here should match the similar chunk for determining
5112 : // inlineStyleCoord and blockStyleCoord in
5113 : // nsFrame::ComputeSizeWithIntrinsicDimensions().
5114 0 : const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
5115 0 : if (flexBasis->GetUnit() != eStyleUnit_Auto) {
5116 0 : if (isInlineFlexItem) {
5117 0 : inlineStyleCoord = flexBasis;
5118 : } else {
5119 : // One caveat for vertical flex items: We don't support enumerated
5120 : // values (e.g. "max-content") for height properties yet. So, if our
5121 : // computed flex-basis is an enumerated value, we'll just behave as if
5122 : // it were "auto", which means "use the main-size property after all"
5123 : // (which is "height", in this case).
5124 : // NOTE: Once we support intrinsic sizing keywords for "height",
5125 : // we should remove this check.
5126 0 : if (flexBasis->GetUnit() != eStyleUnit_Enumerated) {
5127 0 : blockStyleCoord = flexBasis;
5128 : }
5129 : }
5130 : }
5131 : }
5132 :
5133 : // Compute inline-axis size
5134 :
5135 394 : if (inlineStyleCoord->GetUnit() != eStyleUnit_Auto) {
5136 24 : result.ISize(aWM) =
5137 12 : ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
5138 12 : boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
5139 : *inlineStyleCoord, aFlags);
5140 382 : } else if (MOZ_UNLIKELY(isGridItem) &&
5141 0 : !IS_TRUE_OVERFLOW_CONTAINER(this)) {
5142 : // 'auto' inline-size for grid-level box - fill the CB for 'stretch' /
5143 : // 'normal' and clamp it to the CB if requested:
5144 0 : bool stretch = false;
5145 0 : if (!(aFlags & nsIFrame::eShrinkWrap) &&
5146 0 : !StyleMargin()->HasInlineAxisAuto(aWM)) {
5147 : auto inlineAxisAlignment =
5148 0 : aWM.IsOrthogonalTo(alignCB->GetWritingMode()) ?
5149 0 : StylePosition()->UsedAlignSelf(alignCB->StyleContext()) :
5150 0 : StylePosition()->UsedJustifySelf(alignCB->StyleContext());
5151 0 : stretch = inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
5152 : inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH;
5153 : }
5154 0 : if (stretch || (aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
5155 0 : auto iSizeToFillCB = std::max(nscoord(0), aCBSize.ISize(aWM) -
5156 0 : aPadding.ISize(aWM) -
5157 0 : aBorder.ISize(aWM) -
5158 0 : aMargin.ISize(aWM));
5159 0 : if (stretch || result.ISize(aWM) > iSizeToFillCB) {
5160 0 : result.ISize(aWM) = iSizeToFillCB;
5161 : }
5162 : }
5163 : }
5164 :
5165 : // Flex items ignore their min & max sizing properties in their
5166 : // flex container's main-axis. (Those properties get applied later in
5167 : // the flexbox algorithm.)
5168 394 : const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM);
5169 394 : nscoord maxISize = NS_UNCONSTRAINEDSIZE;
5170 502 : if (maxISizeCoord.GetUnit() != eStyleUnit_None &&
5171 54 : !(isFlexItem && isInlineFlexItem)) {
5172 54 : maxISize =
5173 54 : ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
5174 54 : boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
5175 : maxISizeCoord, aFlags);
5176 54 : result.ISize(aWM) = std::min(maxISize, result.ISize(aWM));
5177 : }
5178 :
5179 394 : const nsStyleCoord& minISizeCoord = stylePos->MinISize(aWM);
5180 : nscoord minISize;
5181 500 : if (minISizeCoord.GetUnit() != eStyleUnit_Auto &&
5182 53 : !(isFlexItem && isInlineFlexItem)) {
5183 53 : minISize =
5184 53 : ComputeISizeValue(aRenderingContext, aCBSize.ISize(aWM),
5185 53 : boxSizingAdjust.ISize(aWM), boxSizingToMarginEdgeISize,
5186 : minISizeCoord, aFlags);
5187 341 : } else if (MOZ_UNLIKELY(aFlags & eIApplyAutoMinSize)) {
5188 : // This implements "Implied Minimum Size of Grid Items".
5189 : // https://drafts.csswg.org/css-grid/#min-size-auto
5190 0 : minISize = std::min(maxISize, GetMinISize(aRenderingContext));
5191 0 : if (inlineStyleCoord->IsCoordPercentCalcUnit()) {
5192 0 : minISize = std::min(minISize, result.ISize(aWM));
5193 0 : } else if (aFlags & eIClampMarginBoxMinSize) {
5194 : // "if the grid item spans only grid tracks that have a fixed max track
5195 : // sizing function, its automatic minimum size in that dimension is
5196 : // further clamped to less than or equal to the size necessary to fit
5197 : // its margin box within the resulting grid area (flooring at zero)"
5198 : // https://drafts.csswg.org/css-grid/#min-size-auto
5199 0 : auto maxMinISize = std::max(nscoord(0), aCBSize.ISize(aWM) -
5200 0 : aPadding.ISize(aWM) -
5201 0 : aBorder.ISize(aWM) -
5202 0 : aMargin.ISize(aWM));
5203 0 : minISize = std::min(minISize, maxMinISize);
5204 : }
5205 : } else {
5206 : // Treat "min-width: auto" as 0.
5207 : // NOTE: Technically, "auto" is supposed to behave like "min-content" on
5208 : // flex items. However, we don't need to worry about that here, because
5209 : // flex items' min-sizes are intentionally ignored until the flex
5210 : // container explicitly considers them during space distribution.
5211 341 : minISize = 0;
5212 : }
5213 394 : result.ISize(aWM) = std::max(minISize, result.ISize(aWM));
5214 :
5215 : // Compute block-axis size
5216 : // (but not if we have auto bsize or if we received the "eUseAutoBSize"
5217 : // flag -- then, we'll just stick with the bsize that we already calculated
5218 : // in the initial ComputeAutoSize() call.)
5219 394 : if (!(aFlags & nsIFrame::eUseAutoBSize)) {
5220 394 : if (!nsLayoutUtils::IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM))) {
5221 44 : result.BSize(aWM) =
5222 22 : nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
5223 22 : boxSizingAdjust.BSize(aWM),
5224 : *blockStyleCoord);
5225 744 : } else if (MOZ_UNLIKELY(isGridItem) &&
5226 372 : blockStyleCoord->GetUnit() == eStyleUnit_Auto &&
5227 0 : !IS_TRUE_OVERFLOW_CONTAINER(this)) {
5228 0 : auto cbSize = aCBSize.BSize(aWM);
5229 0 : if (cbSize != NS_AUTOHEIGHT) {
5230 : // 'auto' block-size for grid-level box - fill the CB for 'stretch' /
5231 : // 'normal' and clamp it to the CB if requested:
5232 0 : bool stretch = false;
5233 0 : if (!StyleMargin()->HasBlockAxisAuto(aWM)) {
5234 : auto blockAxisAlignment =
5235 0 : !aWM.IsOrthogonalTo(alignCB->GetWritingMode()) ?
5236 0 : StylePosition()->UsedAlignSelf(alignCB->StyleContext()) :
5237 0 : StylePosition()->UsedJustifySelf(alignCB->StyleContext());
5238 0 : stretch = blockAxisAlignment == NS_STYLE_ALIGN_NORMAL ||
5239 : blockAxisAlignment == NS_STYLE_ALIGN_STRETCH;
5240 : }
5241 0 : if (stretch || (aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize)) {
5242 0 : auto bSizeToFillCB = std::max(nscoord(0), cbSize -
5243 0 : aPadding.BSize(aWM) -
5244 0 : aBorder.BSize(aWM) -
5245 0 : aMargin.BSize(aWM));
5246 0 : if (stretch || (result.BSize(aWM) != NS_AUTOHEIGHT &&
5247 0 : result.BSize(aWM) > bSizeToFillCB)) {
5248 0 : result.BSize(aWM) = bSizeToFillCB;
5249 : }
5250 : }
5251 : }
5252 : }
5253 : }
5254 :
5255 394 : const nsStyleCoord& maxBSizeCoord = stylePos->MaxBSize(aWM);
5256 :
5257 394 : if (result.BSize(aWM) != NS_UNCONSTRAINEDSIZE) {
5258 27 : if (!nsLayoutUtils::IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) &&
5259 0 : !(isFlexItem && !isInlineFlexItem)) {
5260 : nscoord maxBSize =
5261 0 : nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
5262 0 : boxSizingAdjust.BSize(aWM),
5263 0 : maxBSizeCoord);
5264 0 : result.BSize(aWM) = std::min(maxBSize, result.BSize(aWM));
5265 : }
5266 :
5267 27 : const nsStyleCoord& minBSizeCoord = stylePos->MinBSize(aWM);
5268 :
5269 29 : if (!nsLayoutUtils::IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) &&
5270 1 : !(isFlexItem && !isInlineFlexItem)) {
5271 : nscoord minBSize =
5272 1 : nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
5273 1 : boxSizingAdjust.BSize(aWM),
5274 1 : minBSizeCoord);
5275 1 : result.BSize(aWM) = std::max(minBSize, result.BSize(aWM));
5276 : }
5277 : }
5278 :
5279 394 : const nsStyleDisplay *disp = StyleDisplay();
5280 394 : if (IsThemed(disp)) {
5281 0 : LayoutDeviceIntSize widget;
5282 0 : bool canOverride = true;
5283 0 : nsPresContext *presContext = PresContext();
5284 0 : presContext->GetTheme()->
5285 0 : GetMinimumWidgetSize(presContext, this, disp->mAppearance,
5286 0 : &widget, &canOverride);
5287 :
5288 : // Convert themed widget's physical dimensions to logical coords
5289 : LogicalSize size(aWM,
5290 0 : nsSize(presContext->DevPixelsToAppUnits(widget.width),
5291 0 : presContext->DevPixelsToAppUnits(widget.height)));
5292 :
5293 : // GMWS() returns border-box; we need content-box
5294 0 : size.ISize(aWM) -= aBorder.ISize(aWM) + aPadding.ISize(aWM);
5295 0 : size.BSize(aWM) -= aBorder.BSize(aWM) + aPadding.BSize(aWM);
5296 :
5297 0 : if (size.BSize(aWM) > result.BSize(aWM) || !canOverride) {
5298 0 : result.BSize(aWM) = size.BSize(aWM);
5299 : }
5300 0 : if (size.ISize(aWM) > result.ISize(aWM) || !canOverride) {
5301 0 : result.ISize(aWM) = size.ISize(aWM);
5302 : }
5303 : }
5304 :
5305 394 : result.ISize(aWM) = std::max(0, result.ISize(aWM));
5306 394 : result.BSize(aWM) = std::max(0, result.BSize(aWM));
5307 :
5308 394 : return result;
5309 : }
5310 :
5311 : LogicalSize
5312 1 : nsFrame::ComputeSizeWithIntrinsicDimensions(gfxContext* aRenderingContext,
5313 : WritingMode aWM,
5314 : const IntrinsicSize& aIntrinsicSize,
5315 : nsSize aIntrinsicRatio,
5316 : const LogicalSize& aCBSize,
5317 : const LogicalSize& aMargin,
5318 : const LogicalSize& aBorder,
5319 : const LogicalSize& aPadding,
5320 : ComputeSizeFlags aFlags)
5321 : {
5322 1 : const nsStylePosition* stylePos = StylePosition();
5323 1 : const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM);
5324 1 : const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM);
5325 1 : auto* parentFrame = GetParent();
5326 1 : const bool isGridItem = parentFrame && parentFrame->IsGridContainerFrame() &&
5327 1 : !(GetStateBits() & NS_FRAME_OUT_OF_FLOW);
5328 1 : const bool isFlexItem = parentFrame && parentFrame->IsFlexContainerFrame() &&
5329 1 : !(GetStateBits() & NS_FRAME_OUT_OF_FLOW);
5330 1 : bool isInlineFlexItem = false;
5331 2 : Maybe<nsStyleCoord> imposedMainSizeStyleCoord;
5332 :
5333 : // If this is a flex item, and we're measuring its cross size after flexing
5334 : // to resolve its main size, then we need to use the resolved main size
5335 : // that the container provides to us *instead of* the main-size coordinate
5336 : // from our style struct. (Otherwise, we'll be using an irrelevant value in
5337 : // the aspect-ratio calculations below.)
5338 1 : if (isFlexItem) {
5339 : uint32_t flexDirection =
5340 0 : GetParent()->StylePosition()->mFlexDirection;
5341 0 : isInlineFlexItem =
5342 0 : flexDirection == NS_STYLE_FLEX_DIRECTION_ROW ||
5343 : flexDirection == NS_STYLE_FLEX_DIRECTION_ROW_REVERSE;
5344 :
5345 : // If FlexItemMainSizeOverride frame-property is set, then that means the
5346 : // flex container is imposing a main-size on this flex item for it to use
5347 : // as its size in the container's main axis.
5348 : bool didImposeMainSize;
5349 : nscoord imposedMainSize =
5350 0 : GetProperty(nsIFrame::FlexItemMainSizeOverride(), &didImposeMainSize);
5351 0 : if (didImposeMainSize) {
5352 0 : imposedMainSizeStyleCoord.emplace(imposedMainSize,
5353 0 : nsStyleCoord::CoordConstructor);
5354 0 : if (isInlineFlexItem) {
5355 0 : inlineStyleCoord = imposedMainSizeStyleCoord.ptr();
5356 : } else {
5357 0 : blockStyleCoord = imposedMainSizeStyleCoord.ptr();
5358 : }
5359 :
5360 : } else {
5361 : // Flex items use their "flex-basis" property in place of their main-size
5362 : // property (e.g. "width") for sizing purposes, *unless* they have
5363 : // "flex-basis:auto", in which case they use their main-size property
5364 : // after all.
5365 : // NOTE: The logic here should match the similar chunk for determining
5366 : // inlineStyleCoord and blockStyleCoord in nsFrame::ComputeSize().
5367 0 : const nsStyleCoord* flexBasis = &(stylePos->mFlexBasis);
5368 0 : if (flexBasis->GetUnit() != eStyleUnit_Auto) {
5369 0 : if (isInlineFlexItem) {
5370 0 : inlineStyleCoord = flexBasis;
5371 : } else {
5372 : // One caveat for vertical flex items: We don't support enumerated
5373 : // values (e.g. "max-content") for height properties yet. So, if our
5374 : // computed flex-basis is an enumerated value, we'll just behave as if
5375 : // it were "auto", which means "use the main-size property after all"
5376 : // (which is "height", in this case).
5377 : // NOTE: Once we support intrinsic sizing keywords for "height",
5378 : // we should remove this check.
5379 0 : if (flexBasis->GetUnit() != eStyleUnit_Enumerated) {
5380 0 : blockStyleCoord = flexBasis;
5381 : }
5382 : }
5383 : }
5384 : }
5385 : }
5386 :
5387 : // Handle intrinsic sizes and their interaction with
5388 : // {min-,max-,}{width,height} according to the rules in
5389 : // http://www.w3.org/TR/CSS21/visudet.html#min-max-widths
5390 :
5391 : // Note: throughout the following section of the function, I avoid
5392 : // a * (b / c) because of its reduced accuracy relative to a * b / c
5393 : // or (a * b) / c (which are equivalent).
5394 :
5395 1 : const bool isAutoISize = inlineStyleCoord->GetUnit() == eStyleUnit_Auto;
5396 : const bool isAutoBSize =
5397 1 : nsLayoutUtils::IsAutoBSize(*blockStyleCoord, aCBSize.BSize(aWM));
5398 :
5399 1 : LogicalSize boxSizingAdjust(aWM);
5400 1 : if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
5401 0 : boxSizingAdjust = aBorder + aPadding;
5402 : }
5403 : nscoord boxSizingToMarginEdgeISize =
5404 1 : aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) -
5405 1 : boxSizingAdjust.ISize(aWM);
5406 :
5407 : nscoord iSize, minISize, maxISize, bSize, minBSize, maxBSize;
5408 : enum class Stretch {
5409 : // stretch to fill the CB (preserving intrinsic ratio) in the relevant axis
5410 : eStretchPreservingRatio, // XXX not used yet
5411 : // stretch to fill the CB in the relevant axis
5412 : eStretch,
5413 : // no stretching in the relevant axis
5414 : eNoStretch,
5415 : };
5416 : // just to avoid having to type these out everywhere:
5417 1 : const auto eStretchPreservingRatio = Stretch::eStretchPreservingRatio;
5418 1 : const auto eStretch = Stretch::eStretch;
5419 1 : const auto eNoStretch = Stretch::eNoStretch;
5420 :
5421 1 : Stretch stretchI = eNoStretch; // stretch behavior in the inline axis
5422 1 : Stretch stretchB = eNoStretch; // stretch behavior in the block axis
5423 :
5424 1 : const bool isVertical = aWM.IsVertical();
5425 : const nsStyleCoord& isizeCoord =
5426 1 : isVertical ? aIntrinsicSize.height : aIntrinsicSize.width;
5427 1 : const bool hasIntrinsicISize = isizeCoord.GetUnit() == eStyleUnit_Coord;
5428 : nscoord intrinsicISize;
5429 1 : if (hasIntrinsicISize) {
5430 0 : intrinsicISize = std::max(nscoord(0), isizeCoord.GetCoordValue());
5431 : } else {
5432 1 : NS_ASSERTION(isizeCoord.GetUnit() == eStyleUnit_None,
5433 : "unexpected unit");
5434 1 : intrinsicISize = 0;
5435 : }
5436 :
5437 : const nsStyleCoord& bsizeCoord =
5438 1 : isVertical ? aIntrinsicSize.width : aIntrinsicSize.height;
5439 1 : const bool hasIntrinsicBSize = bsizeCoord.GetUnit() == eStyleUnit_Coord;
5440 : nscoord intrinsicBSize;
5441 1 : if (hasIntrinsicBSize) {
5442 1 : intrinsicBSize = std::max(nscoord(0), bsizeCoord.GetCoordValue());
5443 : } else {
5444 0 : NS_ASSERTION(bsizeCoord.GetUnit() == eStyleUnit_None,
5445 : "unexpected unit");
5446 0 : intrinsicBSize = 0;
5447 : }
5448 :
5449 1 : NS_ASSERTION(aIntrinsicRatio.width >= 0 && aIntrinsicRatio.height >= 0,
5450 : "Intrinsic ratio has a negative component!");
5451 1 : LogicalSize logicalRatio(aWM, aIntrinsicRatio);
5452 :
5453 1 : if (!isAutoISize) {
5454 0 : iSize = ComputeISizeValue(aRenderingContext,
5455 0 : aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
5456 0 : boxSizingToMarginEdgeISize, *inlineStyleCoord, aFlags);
5457 1 : } else if (MOZ_UNLIKELY(isGridItem)) {
5458 0 : MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(this));
5459 : // 'auto' inline-size for grid-level box - apply 'stretch' as needed:
5460 0 : auto cbSize = aCBSize.ISize(aWM);
5461 0 : if (cbSize != NS_UNCONSTRAINEDSIZE) {
5462 0 : if (!StyleMargin()->HasInlineAxisAuto(aWM)) {
5463 : auto inlineAxisAlignment =
5464 0 : aWM.IsOrthogonalTo(GetParent()->GetWritingMode()) ?
5465 0 : stylePos->UsedAlignSelf(GetParent()->StyleContext()) :
5466 0 : stylePos->UsedJustifySelf(GetParent()->StyleContext());
5467 : // Note: 'normal' means 'start' for elements with an intrinsic size
5468 : // or ratio in the relevant dimension, otherwise 'stretch'.
5469 : // https://drafts.csswg.org/css-grid/#grid-item-sizing
5470 0 : if ((inlineAxisAlignment == NS_STYLE_ALIGN_NORMAL &&
5471 0 : !hasIntrinsicISize &&
5472 0 : !(logicalRatio.ISize(aWM) > 0)) ||
5473 : inlineAxisAlignment == NS_STYLE_ALIGN_STRETCH) {
5474 0 : stretchI = eStretch;
5475 : }
5476 : }
5477 0 : if (stretchI != eNoStretch ||
5478 0 : (aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
5479 0 : iSize = std::max(nscoord(0), cbSize -
5480 0 : aPadding.ISize(aWM) -
5481 0 : aBorder.ISize(aWM) -
5482 0 : aMargin.ISize(aWM));
5483 : }
5484 : } else {
5485 : // Reset this flag to avoid applying the clamping below.
5486 0 : aFlags = ComputeSizeFlags(aFlags &
5487 : ~ComputeSizeFlags::eIClampMarginBoxMinSize);
5488 : }
5489 : }
5490 :
5491 1 : const nsStyleCoord& maxISizeCoord = stylePos->MaxISize(aWM);
5492 :
5493 1 : if (maxISizeCoord.GetUnit() != eStyleUnit_None &&
5494 0 : !(isFlexItem && isInlineFlexItem)) {
5495 0 : maxISize = ComputeISizeValue(aRenderingContext,
5496 0 : aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
5497 0 : boxSizingToMarginEdgeISize, maxISizeCoord, aFlags);
5498 : } else {
5499 1 : maxISize = nscoord_MAX;
5500 : }
5501 :
5502 : // NOTE: Flex items ignore their min & max sizing properties in their
5503 : // flex container's main-axis. (Those properties get applied later in
5504 : // the flexbox algorithm.)
5505 :
5506 1 : const nsStyleCoord& minISizeCoord = stylePos->MinISize(aWM);
5507 :
5508 1 : if (minISizeCoord.GetUnit() != eStyleUnit_Auto &&
5509 0 : !(isFlexItem && isInlineFlexItem)) {
5510 0 : minISize = ComputeISizeValue(aRenderingContext,
5511 0 : aCBSize.ISize(aWM), boxSizingAdjust.ISize(aWM),
5512 0 : boxSizingToMarginEdgeISize, minISizeCoord, aFlags);
5513 : } else {
5514 : // Treat "min-width: auto" as 0.
5515 : // NOTE: Technically, "auto" is supposed to behave like "min-content" on
5516 : // flex items. However, we don't need to worry about that here, because
5517 : // flex items' min-sizes are intentionally ignored until the flex
5518 : // container explicitly considers them during space distribution.
5519 1 : minISize = 0;
5520 : }
5521 :
5522 1 : if (!isAutoBSize) {
5523 1 : bSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
5524 1 : boxSizingAdjust.BSize(aWM),
5525 1 : *blockStyleCoord);
5526 0 : } else if (MOZ_UNLIKELY(isGridItem)) {
5527 0 : MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(this));
5528 : // 'auto' block-size for grid-level box - apply 'stretch' as needed:
5529 0 : auto cbSize = aCBSize.BSize(aWM);
5530 0 : if (cbSize != NS_AUTOHEIGHT) {
5531 0 : if (!StyleMargin()->HasBlockAxisAuto(aWM)) {
5532 : auto blockAxisAlignment =
5533 0 : !aWM.IsOrthogonalTo(GetParent()->GetWritingMode()) ?
5534 0 : stylePos->UsedAlignSelf(GetParent()->StyleContext()) :
5535 0 : stylePos->UsedJustifySelf(GetParent()->StyleContext());
5536 : // Note: 'normal' means 'start' for elements with an intrinsic size
5537 : // or ratio in the relevant dimension, otherwise 'stretch'.
5538 : // https://drafts.csswg.org/css-grid/#grid-item-sizing
5539 0 : if ((blockAxisAlignment == NS_STYLE_ALIGN_NORMAL &&
5540 0 : !hasIntrinsicBSize &&
5541 0 : !(logicalRatio.BSize(aWM) > 0)) ||
5542 : blockAxisAlignment == NS_STYLE_ALIGN_STRETCH) {
5543 0 : stretchB = eStretch;
5544 : }
5545 : }
5546 0 : if (stretchB != eNoStretch ||
5547 0 : (aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize)) {
5548 0 : bSize = std::max(nscoord(0), cbSize -
5549 0 : aPadding.BSize(aWM) -
5550 0 : aBorder.BSize(aWM) -
5551 0 : aMargin.BSize(aWM));
5552 : }
5553 : } else {
5554 : // Reset this flag to avoid applying the clamping below.
5555 0 : aFlags = ComputeSizeFlags(aFlags &
5556 : ~ComputeSizeFlags::eBClampMarginBoxMinSize);
5557 : }
5558 : }
5559 :
5560 1 : const nsStyleCoord& maxBSizeCoord = stylePos->MaxBSize(aWM);
5561 :
5562 1 : if (!nsLayoutUtils::IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) &&
5563 0 : !(isFlexItem && !isInlineFlexItem)) {
5564 0 : maxBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
5565 0 : boxSizingAdjust.BSize(aWM), maxBSizeCoord);
5566 : } else {
5567 1 : maxBSize = nscoord_MAX;
5568 : }
5569 :
5570 1 : const nsStyleCoord& minBSizeCoord = stylePos->MinBSize(aWM);
5571 :
5572 1 : if (!nsLayoutUtils::IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) &&
5573 0 : !(isFlexItem && !isInlineFlexItem)) {
5574 0 : minBSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
5575 0 : boxSizingAdjust.BSize(aWM), minBSizeCoord);
5576 : } else {
5577 1 : minBSize = 0;
5578 : }
5579 :
5580 1 : NS_ASSERTION(aCBSize.ISize(aWM) != NS_UNCONSTRAINEDSIZE,
5581 : "Our containing block must not have unconstrained inline-size!");
5582 :
5583 : // Now calculate the used values for iSize and bSize:
5584 :
5585 1 : if (isAutoISize) {
5586 1 : if (isAutoBSize) {
5587 :
5588 : // 'auto' iSize, 'auto' bSize
5589 :
5590 : // Get tentative values - CSS 2.1 sections 10.3.2 and 10.6.2:
5591 :
5592 : nscoord tentISize, tentBSize;
5593 :
5594 0 : if (hasIntrinsicISize) {
5595 0 : tentISize = intrinsicISize;
5596 0 : } else if (hasIntrinsicBSize && logicalRatio.BSize(aWM) > 0) {
5597 0 : tentISize = NSCoordMulDiv(intrinsicBSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
5598 0 : } else if (logicalRatio.ISize(aWM) > 0) {
5599 0 : tentISize = aCBSize.ISize(aWM) - boxSizingToMarginEdgeISize; // XXX scrollbar?
5600 0 : if (tentISize < 0) tentISize = 0;
5601 : } else {
5602 0 : tentISize = nsPresContext::CSSPixelsToAppUnits(300);
5603 : }
5604 :
5605 : // If we need to clamp the inline size to fit the CB, we use the 'stretch'
5606 : // or 'normal' codepath. We use the ratio-preserving 'normal' codepath
5607 : // unless we have 'stretch' in the other axis.
5608 0 : if ((aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) &&
5609 0 : stretchI != eStretch && tentISize > iSize) {
5610 0 : stretchI = (stretchB == eStretch ? eStretch : eStretchPreservingRatio);
5611 : }
5612 :
5613 0 : if (hasIntrinsicBSize) {
5614 0 : tentBSize = intrinsicBSize;
5615 0 : } else if (logicalRatio.ISize(aWM) > 0) {
5616 0 : tentBSize = NSCoordMulDiv(tentISize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
5617 : } else {
5618 0 : tentBSize = nsPresContext::CSSPixelsToAppUnits(150);
5619 : }
5620 :
5621 : // (ditto the comment about clamping the inline size above)
5622 0 : if ((aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize) &&
5623 0 : stretchB != eStretch && tentBSize > bSize) {
5624 0 : stretchB = (stretchI == eStretch ? eStretch : eStretchPreservingRatio);
5625 : }
5626 :
5627 0 : if (aIntrinsicRatio != nsSize(0, 0)) {
5628 0 : if (stretchI == eStretch) {
5629 0 : tentISize = iSize; // * / 'stretch'
5630 0 : if (stretchB == eStretch) {
5631 0 : tentBSize = bSize; // 'stretch' / 'stretch'
5632 0 : } else if (stretchB == eStretchPreservingRatio && logicalRatio.ISize(aWM) > 0) {
5633 : // 'normal' / 'stretch'
5634 0 : tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
5635 : }
5636 0 : } else if (stretchB == eStretch) {
5637 0 : tentBSize = bSize; // 'stretch' / * (except 'stretch')
5638 0 : if (stretchI == eStretchPreservingRatio && logicalRatio.BSize(aWM) > 0) {
5639 : // 'stretch' / 'normal'
5640 0 : tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
5641 : }
5642 0 : } else if (stretchI == eStretchPreservingRatio) {
5643 0 : tentISize = iSize; // * (except 'stretch') / 'normal'
5644 0 : if (logicalRatio.ISize(aWM) > 0) {
5645 0 : tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
5646 : }
5647 0 : if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
5648 : // Stretch within the CB size with preserved intrinsic ratio.
5649 0 : tentBSize = bSize; // 'normal' / 'normal'
5650 0 : if (logicalRatio.BSize(aWM) > 0) {
5651 0 : tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
5652 : }
5653 : }
5654 0 : } else if (stretchB == eStretchPreservingRatio) {
5655 0 : tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
5656 0 : if (logicalRatio.BSize(aWM) > 0) {
5657 0 : tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
5658 : }
5659 : }
5660 : }
5661 :
5662 : // ComputeAutoSizeWithIntrinsicDimensions preserves the ratio when applying
5663 : // the min/max-size. We don't want that when we have 'stretch' in either
5664 : // axis because tentISize/tentBSize is likely not according to ratio now.
5665 0 : if (aIntrinsicRatio != nsSize(0, 0) &&
5666 0 : stretchI != eStretch && stretchB != eStretch) {
5667 : nsSize autoSize = nsLayoutUtils::
5668 : ComputeAutoSizeWithIntrinsicDimensions(minISize, minBSize,
5669 : maxISize, maxBSize,
5670 0 : tentISize, tentBSize);
5671 : // The nsSize that ComputeAutoSizeWithIntrinsicDimensions returns will
5672 : // actually contain logical values if the parameters passed to it were
5673 : // logical coordinates, so we do NOT perform a physical-to-logical
5674 : // conversion here, but just assign the fields directly to our result.
5675 0 : iSize = autoSize.width;
5676 0 : bSize = autoSize.height;
5677 : } else {
5678 : // Not honoring an intrinsic ratio: clamp the dimensions independently.
5679 0 : iSize = NS_CSS_MINMAX(tentISize, minISize, maxISize);
5680 0 : bSize = NS_CSS_MINMAX(tentBSize, minBSize, maxBSize);
5681 : }
5682 : } else {
5683 :
5684 : // 'auto' iSize, non-'auto' bSize
5685 1 : bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
5686 1 : if (stretchI != eStretch) {
5687 1 : if (logicalRatio.BSize(aWM) > 0) {
5688 0 : iSize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
5689 1 : } else if (hasIntrinsicISize) {
5690 0 : if (!((aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) &&
5691 : intrinsicISize > iSize)) {
5692 0 : iSize = intrinsicISize;
5693 : } // else - leave iSize as is to fill the CB
5694 : } else {
5695 1 : iSize = nsPresContext::CSSPixelsToAppUnits(300);
5696 : }
5697 : } // else - leave iSize as is to fill the CB
5698 1 : iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
5699 :
5700 : }
5701 : } else {
5702 0 : if (isAutoBSize) {
5703 :
5704 : // non-'auto' iSize, 'auto' bSize
5705 0 : iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
5706 0 : if (stretchB != eStretch) {
5707 0 : if (logicalRatio.ISize(aWM) > 0) {
5708 0 : bSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
5709 0 : } else if (hasIntrinsicBSize) {
5710 0 : if (!((aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize) &&
5711 : intrinsicBSize > bSize)) {
5712 0 : bSize = intrinsicBSize;
5713 : } // else - leave bSize as is to fill the CB
5714 : } else {
5715 0 : bSize = nsPresContext::CSSPixelsToAppUnits(150);
5716 : }
5717 : } // else - leave bSize as is to fill the CB
5718 0 : bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
5719 :
5720 : } else {
5721 :
5722 : // non-'auto' iSize, non-'auto' bSize
5723 0 : iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
5724 0 : bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
5725 :
5726 : }
5727 : }
5728 :
5729 2 : return LogicalSize(aWM, iSize, bSize);
5730 : }
5731 :
5732 : nsRect
5733 0 : nsIFrame::ComputeTightBounds(DrawTarget* aDrawTarget) const
5734 : {
5735 0 : return GetVisualOverflowRect();
5736 : }
5737 :
5738 : nsRect
5739 0 : nsFrame::ComputeSimpleTightBounds(DrawTarget* aDrawTarget) const
5740 : {
5741 0 : if (StyleOutline()->ShouldPaintOutline() || StyleBorder()->HasBorder() ||
5742 0 : !StyleBackground()->IsTransparent(this) ||
5743 0 : StyleDisplay()->mAppearance) {
5744 : // Not necessarily tight, due to clipping, negative
5745 : // outline-offset, and lots of other issues, but that's OK
5746 0 : return GetVisualOverflowRect();
5747 : }
5748 :
5749 0 : nsRect r(0, 0, 0, 0);
5750 0 : ChildListIterator lists(this);
5751 0 : for (; !lists.IsDone(); lists.Next()) {
5752 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
5753 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
5754 0 : nsIFrame* child = childFrames.get();
5755 0 : r.UnionRect(r, child->ComputeTightBounds(aDrawTarget) + child->GetPosition());
5756 : }
5757 : }
5758 0 : return r;
5759 : }
5760 :
5761 : /* virtual */ nsresult
5762 0 : nsIFrame::GetPrefWidthTightBounds(gfxContext* aContext,
5763 : nscoord* aX,
5764 : nscoord* aXMost)
5765 : {
5766 0 : return NS_ERROR_NOT_IMPLEMENTED;
5767 : }
5768 :
5769 : /* virtual */
5770 : LogicalSize
5771 52 : nsFrame::ComputeAutoSize(gfxContext* aRenderingContext,
5772 : WritingMode aWM,
5773 : const mozilla::LogicalSize& aCBSize,
5774 : nscoord aAvailableISize,
5775 : const mozilla::LogicalSize& aMargin,
5776 : const mozilla::LogicalSize& aBorder,
5777 : const mozilla::LogicalSize& aPadding,
5778 : ComputeSizeFlags aFlags)
5779 : {
5780 : // Use basic shrink-wrapping as a default implementation.
5781 52 : LogicalSize result(aWM, 0xdeadbeef, NS_UNCONSTRAINEDSIZE);
5782 :
5783 : // don't bother setting it if the result won't be used
5784 52 : if (StylePosition()->ISize(aWM).GetUnit() == eStyleUnit_Auto) {
5785 104 : nscoord availBased = aAvailableISize - aMargin.ISize(aWM) -
5786 104 : aBorder.ISize(aWM) - aPadding.ISize(aWM);
5787 52 : result.ISize(aWM) = ShrinkWidthToFit(aRenderingContext, availBased, aFlags);
5788 : }
5789 52 : return result;
5790 : }
5791 :
5792 : nscoord
5793 171 : nsFrame::ShrinkWidthToFit(gfxContext* aRenderingContext,
5794 : nscoord aISizeInCB,
5795 : ComputeSizeFlags aFlags)
5796 : {
5797 : // If we're a container for font size inflation, then shrink
5798 : // wrapping inside of us should not apply font size inflation.
5799 342 : AutoMaybeDisableFontInflation an(this);
5800 :
5801 : nscoord result;
5802 171 : nscoord minISize = GetMinISize(aRenderingContext);
5803 171 : if (minISize > aISizeInCB) {
5804 17 : const bool clamp = aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize;
5805 17 : result = MOZ_UNLIKELY(clamp) ? aISizeInCB : minISize;
5806 : } else {
5807 154 : nscoord prefISize = GetPrefISize(aRenderingContext);
5808 154 : if (prefISize > aISizeInCB) {
5809 2 : result = aISizeInCB;
5810 : } else {
5811 152 : result = prefISize;
5812 : }
5813 : }
5814 342 : return result;
5815 : }
5816 :
5817 : nscoord
5818 225 : nsIFrame::ComputeISizeValue(gfxContext* aRenderingContext,
5819 : nscoord aContainingBlockISize,
5820 : nscoord aContentEdgeToBoxSizing,
5821 : nscoord aBoxSizingToMarginEdge,
5822 : const nsStyleCoord& aCoord,
5823 : ComputeSizeFlags aFlags)
5824 : {
5825 225 : NS_PRECONDITION(aRenderingContext, "non-null rendering context expected");
5826 225 : LAYOUT_WARN_IF_FALSE(aContainingBlockISize != NS_UNCONSTRAINEDSIZE,
5827 : "have unconstrained inline-size; this should only result from "
5828 : "very large sizes, not attempts at intrinsic inline-size "
5829 : "calculation");
5830 225 : NS_PRECONDITION(aContainingBlockISize >= 0,
5831 : "inline-size less than zero");
5832 :
5833 : nscoord result;
5834 225 : if (aCoord.IsCoordPercentCalcUnit()) {
5835 225 : result = nsRuleNode::ComputeCoordPercentCalc(aCoord,
5836 : aContainingBlockISize);
5837 : // The result of a calc() expression might be less than 0; we
5838 : // should clamp at runtime (below). (Percentages and coords that
5839 : // are less than 0 have already been dropped by the parser.)
5840 225 : result -= aContentEdgeToBoxSizing;
5841 : } else {
5842 0 : MOZ_ASSERT(eStyleUnit_Enumerated == aCoord.GetUnit());
5843 : // If 'this' is a container for font size inflation, then shrink
5844 : // wrapping inside of it should not apply font size inflation.
5845 0 : AutoMaybeDisableFontInflation an(this);
5846 :
5847 0 : int32_t val = aCoord.GetIntValue();
5848 0 : switch (val) {
5849 : case NS_STYLE_WIDTH_MAX_CONTENT:
5850 0 : result = GetPrefISize(aRenderingContext);
5851 0 : NS_ASSERTION(result >= 0, "inline-size less than zero");
5852 0 : break;
5853 : case NS_STYLE_WIDTH_MIN_CONTENT:
5854 0 : result = GetMinISize(aRenderingContext);
5855 0 : NS_ASSERTION(result >= 0, "inline-size less than zero");
5856 0 : if (MOZ_UNLIKELY(aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
5857 0 : auto available = aContainingBlockISize -
5858 0 : (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
5859 0 : result = std::min(available, result);
5860 : }
5861 0 : break;
5862 : case NS_STYLE_WIDTH_FIT_CONTENT:
5863 : {
5864 0 : nscoord pref = GetPrefISize(aRenderingContext),
5865 0 : min = GetMinISize(aRenderingContext),
5866 0 : fill = aContainingBlockISize -
5867 0 : (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
5868 0 : if (MOZ_UNLIKELY(aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize)) {
5869 0 : min = std::min(min, fill);
5870 : }
5871 0 : result = std::max(min, std::min(pref, fill));
5872 0 : NS_ASSERTION(result >= 0, "inline-size less than zero");
5873 : }
5874 0 : break;
5875 : case NS_STYLE_WIDTH_AVAILABLE:
5876 0 : result = aContainingBlockISize -
5877 0 : (aBoxSizingToMarginEdge + aContentEdgeToBoxSizing);
5878 : }
5879 : }
5880 :
5881 225 : return std::max(0, result);
5882 : }
5883 :
5884 : void
5885 635 : nsFrame::DidReflow(nsPresContext* aPresContext,
5886 : const ReflowInput* aReflowInput,
5887 : nsDidReflowStatus aStatus)
5888 : {
5889 635 : NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS,
5890 : ("nsFrame::DidReflow: aStatus=%d", static_cast<uint32_t>(aStatus)));
5891 :
5892 635 : nsSVGEffects::InvalidateDirectRenderingObservers(this, nsSVGEffects::INVALIDATE_REFLOW);
5893 :
5894 635 : if (nsDidReflowStatus::FINISHED == aStatus) {
5895 : mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY |
5896 635 : NS_FRAME_HAS_DIRTY_CHILDREN);
5897 : }
5898 :
5899 : // Notify the percent bsize observer if there is a percent bsize.
5900 : // The observer may be able to initiate another reflow with a computed
5901 : // bsize. This happens in the case where a table cell has no computed
5902 : // bsize but can fabricate one when the cell bsize is known.
5903 635 : if (aReflowInput && aReflowInput->mPercentBSizeObserver &&
5904 0 : !GetPrevInFlow()) {
5905 : const nsStyleCoord &bsize =
5906 0 : aReflowInput->mStylePosition->BSize(aReflowInput->GetWritingMode());
5907 0 : if (bsize.HasPercent()) {
5908 0 : aReflowInput->mPercentBSizeObserver->NotifyPercentBSize(*aReflowInput);
5909 : }
5910 : }
5911 :
5912 635 : aPresContext->ReflowedFrame();
5913 635 : }
5914 :
5915 : void
5916 170 : nsFrame::FinishReflowWithAbsoluteFrames(nsPresContext* aPresContext,
5917 : ReflowOutput& aDesiredSize,
5918 : const ReflowInput& aReflowInput,
5919 : nsReflowStatus& aStatus,
5920 : bool aConstrainBSize)
5921 : {
5922 170 : ReflowAbsoluteFrames(aPresContext, aDesiredSize, aReflowInput, aStatus, aConstrainBSize);
5923 :
5924 170 : FinishAndStoreOverflow(&aDesiredSize, aReflowInput.mStyleDisplay);
5925 170 : }
5926 :
5927 : void
5928 202 : nsFrame::ReflowAbsoluteFrames(nsPresContext* aPresContext,
5929 : ReflowOutput& aDesiredSize,
5930 : const ReflowInput& aReflowInput,
5931 : nsReflowStatus& aStatus,
5932 : bool aConstrainBSize)
5933 : {
5934 202 : if (HasAbsolutelyPositionedChildren()) {
5935 0 : nsAbsoluteContainingBlock* absoluteContainer = GetAbsoluteContainingBlock();
5936 :
5937 : // Let the absolutely positioned container reflow any absolutely positioned
5938 : // child frames that need to be reflowed
5939 :
5940 : // The containing block for the abs pos kids is formed by our padding edge.
5941 0 : nsMargin usedBorder = GetUsedBorder();
5942 : nscoord containingBlockWidth =
5943 0 : std::max(0, aDesiredSize.Width() - usedBorder.LeftRight());
5944 : nscoord containingBlockHeight =
5945 0 : std::max(0, aDesiredSize.Height() - usedBorder.TopBottom());
5946 0 : nsContainerFrame* container = do_QueryFrame(this);
5947 0 : NS_ASSERTION(container, "Abs-pos children only supported on container frames for now");
5948 :
5949 0 : nsRect containingBlock(0, 0, containingBlockWidth, containingBlockHeight);
5950 : AbsPosReflowFlags flags =
5951 0 : AbsPosReflowFlags::eCBWidthAndHeightChanged; // XXX could be optimized
5952 0 : if (aConstrainBSize) {
5953 0 : flags |= AbsPosReflowFlags::eConstrainHeight;
5954 : }
5955 0 : absoluteContainer->Reflow(container, aPresContext, aReflowInput, aStatus,
5956 : containingBlock, flags,
5957 0 : &aDesiredSize.mOverflowAreas);
5958 : }
5959 202 : }
5960 :
5961 : void
5962 0 : nsFrame::PushDirtyBitToAbsoluteFrames()
5963 : {
5964 0 : if (!(GetStateBits() & NS_FRAME_IS_DIRTY)) {
5965 0 : return; // No dirty bit to push.
5966 : }
5967 0 : if (!HasAbsolutelyPositionedChildren()) {
5968 0 : return; // No absolute children to push to.
5969 : }
5970 0 : GetAbsoluteContainingBlock()->MarkAllFramesDirty();
5971 : }
5972 :
5973 : /* virtual */ bool
5974 100 : nsFrame::CanContinueTextRun() const
5975 : {
5976 : // By default, a frame will *not* allow a text run to be continued
5977 : // through it.
5978 100 : return false;
5979 : }
5980 :
5981 : void
5982 0 : nsFrame::Reflow(nsPresContext* aPresContext,
5983 : ReflowOutput& aDesiredSize,
5984 : const ReflowInput& aReflowInput,
5985 : nsReflowStatus& aStatus)
5986 : {
5987 0 : MarkInReflow();
5988 0 : DO_GLOBAL_REFLOW_COUNT("nsFrame");
5989 0 : aDesiredSize.ClearSize();
5990 0 : aStatus.Reset();
5991 0 : NS_FRAME_SET_TRUNCATION(aStatus, aReflowInput, aDesiredSize);
5992 0 : }
5993 :
5994 : nsresult
5995 0 : nsFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo)
5996 : {
5997 0 : NS_NOTREACHED("should only be called for text frames");
5998 0 : return NS_OK;
5999 : }
6000 :
6001 : nsresult
6002 144 : nsFrame::AttributeChanged(int32_t aNameSpaceID,
6003 : nsIAtom* aAttribute,
6004 : int32_t aModType)
6005 : {
6006 144 : return NS_OK;
6007 : }
6008 :
6009 : // Flow member functions
6010 :
6011 : nsSplittableType
6012 0 : nsFrame::GetSplittableType() const
6013 : {
6014 0 : return NS_FRAME_NOT_SPLITTABLE;
6015 : }
6016 :
6017 1344 : nsIFrame* nsFrame::GetPrevContinuation() const
6018 : {
6019 1344 : return nullptr;
6020 : }
6021 :
6022 : void
6023 0 : nsFrame::SetPrevContinuation(nsIFrame* aPrevContinuation)
6024 : {
6025 0 : MOZ_ASSERT(false, "not splittable");
6026 : }
6027 :
6028 858 : nsIFrame* nsFrame::GetNextContinuation() const
6029 : {
6030 858 : return nullptr;
6031 : }
6032 :
6033 : void
6034 0 : nsFrame::SetNextContinuation(nsIFrame*)
6035 : {
6036 0 : MOZ_ASSERT(false, "not splittable");
6037 : }
6038 :
6039 0 : nsIFrame* nsFrame::GetPrevInFlowVirtual() const
6040 : {
6041 0 : return nullptr;
6042 : }
6043 :
6044 : void
6045 0 : nsFrame::SetPrevInFlow(nsIFrame* aPrevInFlow)
6046 : {
6047 0 : MOZ_ASSERT(false, "not splittable");
6048 : }
6049 :
6050 25 : nsIFrame* nsFrame::GetNextInFlowVirtual() const
6051 : {
6052 25 : return nullptr;
6053 : }
6054 :
6055 : void
6056 0 : nsFrame::SetNextInFlow(nsIFrame*)
6057 : {
6058 0 : MOZ_ASSERT(false, "not splittable");
6059 : }
6060 :
6061 11 : nsIFrame* nsIFrame::GetTailContinuation()
6062 : {
6063 11 : nsIFrame* frame = this;
6064 11 : while (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
6065 0 : frame = frame->GetPrevContinuation();
6066 0 : NS_ASSERTION(frame, "first continuation can't be overflow container");
6067 : }
6068 22 : for (nsIFrame* next = frame->GetNextContinuation();
6069 11 : next && !(next->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER);
6070 0 : next = frame->GetNextContinuation()) {
6071 0 : frame = next;
6072 : }
6073 11 : NS_POSTCONDITION(frame, "illegal state in continuation chain.");
6074 11 : return frame;
6075 : }
6076 :
6077 : // Associated view object
6078 : void
6079 71 : nsIFrame::SetView(nsView* aView)
6080 : {
6081 71 : if (aView) {
6082 71 : aView->SetFrame(this);
6083 :
6084 : #ifdef DEBUG
6085 71 : LayoutFrameType frameType = Type();
6086 71 : NS_ASSERTION(frameType == LayoutFrameType::SubDocument ||
6087 : frameType == LayoutFrameType::ListControl ||
6088 : frameType == LayoutFrameType::Object ||
6089 : frameType == LayoutFrameType::Viewport ||
6090 : frameType == LayoutFrameType::MenuPopup,
6091 : "Only specific frame types can have an nsView");
6092 : #endif
6093 :
6094 : // Store the view on the frame.
6095 71 : SetViewInternal(aView);
6096 :
6097 : // Set the frame state bit that says the frame has a view
6098 71 : AddStateBits(NS_FRAME_HAS_VIEW);
6099 :
6100 : // Let all of the ancestors know they have a descendant with a view.
6101 256 : for (nsIFrame* f = GetParent();
6102 128 : f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
6103 : f = f->GetParent())
6104 57 : f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
6105 : } else {
6106 0 : MOZ_ASSERT_UNREACHABLE("Destroying a view while the frame is alive?");
6107 : RemoveStateBits(NS_FRAME_HAS_VIEW);
6108 : SetViewInternal(nullptr);
6109 : }
6110 71 : }
6111 :
6112 : // Find the first geometric parent that has a view
6113 0 : nsIFrame* nsIFrame::GetAncestorWithView() const
6114 : {
6115 0 : for (nsIFrame* f = GetParent(); nullptr != f; f = f->GetParent()) {
6116 0 : if (f->HasView()) {
6117 0 : return f;
6118 : }
6119 : }
6120 0 : return nullptr;
6121 : }
6122 :
6123 4938 : nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const
6124 : {
6125 4938 : NS_PRECONDITION(aOther,
6126 : "Must have frame for destination coordinate system!");
6127 :
6128 4938 : NS_ASSERTION(PresContext() == aOther->PresContext(),
6129 : "GetOffsetTo called on frames in different documents");
6130 :
6131 4938 : nsPoint offset(0, 0);
6132 : const nsIFrame* f;
6133 9868 : for (f = this; f != aOther && f; f = f->GetParent()) {
6134 4930 : offset += f->GetPosition();
6135 : }
6136 :
6137 4938 : if (f != aOther) {
6138 : // Looks like aOther wasn't an ancestor of |this|. So now we have
6139 : // the root-frame-relative position of |this| in |offset|. Convert back
6140 : // to the coordinates of aOther
6141 42 : while (aOther) {
6142 18 : offset -= aOther->GetPosition();
6143 18 : aOther = aOther->GetParent();
6144 : }
6145 : }
6146 :
6147 4938 : return offset;
6148 : }
6149 :
6150 3542 : nsPoint nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther) const
6151 : {
6152 3542 : return GetOffsetToCrossDoc(aOther, PresContext()->AppUnitsPerDevPixel());
6153 : }
6154 :
6155 : nsPoint
6156 3606 : nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const
6157 : {
6158 3606 : NS_PRECONDITION(aOther,
6159 : "Must have frame for destination coordinate system!");
6160 3606 : NS_ASSERTION(PresContext()->GetRootPresContext() ==
6161 : aOther->PresContext()->GetRootPresContext(),
6162 : "trying to get the offset between frames in different document "
6163 : "hierarchies?");
6164 7212 : if (PresContext()->GetRootPresContext() !=
6165 3606 : aOther->PresContext()->GetRootPresContext()) {
6166 : // crash right away, we are almost certainly going to crash anyway.
6167 0 : MOZ_CRASH("trying to get the offset between frames in different "
6168 : "document hierarchies?");
6169 : }
6170 :
6171 3606 : const nsIFrame* root = nullptr;
6172 : // offset will hold the final offset
6173 : // docOffset holds the currently accumulated offset at the current APD, it
6174 : // will be converted and added to offset when the current APD changes.
6175 3606 : nsPoint offset(0, 0), docOffset(0, 0);
6176 3606 : const nsIFrame* f = this;
6177 3606 : int32_t currAPD = PresContext()->AppUnitsPerDevPixel();
6178 20294 : while (f && f != aOther) {
6179 8344 : docOffset += f->GetPosition();
6180 8344 : nsIFrame* parent = f->GetParent();
6181 8344 : if (parent) {
6182 8280 : f = parent;
6183 : } else {
6184 64 : nsPoint newOffset(0, 0);
6185 64 : root = f;
6186 64 : f = nsLayoutUtils::GetCrossDocParentFrame(f, &newOffset);
6187 64 : int32_t newAPD = f ? f->PresContext()->AppUnitsPerDevPixel() : 0;
6188 64 : if (!f || newAPD != currAPD) {
6189 : // Convert docOffset to the right APD and add it to offset.
6190 64 : offset += docOffset.ScaleToOtherAppUnits(currAPD, aAPD);
6191 64 : docOffset.x = docOffset.y = 0;
6192 : }
6193 64 : currAPD = newAPD;
6194 64 : docOffset += newOffset;
6195 : }
6196 : }
6197 3606 : if (f == aOther) {
6198 3542 : offset += docOffset.ScaleToOtherAppUnits(currAPD, aAPD);
6199 : } else {
6200 : // Looks like aOther wasn't an ancestor of |this|. So now we have
6201 : // the root-document-relative position of |this| in |offset|. Subtract the
6202 : // root-document-relative position of |aOther| from |offset|.
6203 : // This call won't try to recurse again because root is an ancestor of
6204 : // aOther.
6205 64 : nsPoint negOffset = aOther->GetOffsetToCrossDoc(root, aAPD);
6206 64 : offset -= negOffset;
6207 : }
6208 :
6209 3606 : return offset;
6210 : }
6211 :
6212 0 : CSSIntRect nsIFrame::GetScreenRect() const
6213 : {
6214 0 : return CSSIntRect::FromAppUnitsToNearest(GetScreenRectInAppUnits());
6215 : }
6216 :
6217 8 : nsRect nsIFrame::GetScreenRectInAppUnits() const
6218 : {
6219 8 : nsPresContext* presContext = PresContext();
6220 : nsIFrame* rootFrame =
6221 8 : presContext->PresShell()->FrameManager()->GetRootFrame();
6222 8 : nsPoint rootScreenPos(0, 0);
6223 8 : nsPoint rootFrameOffsetInParent(0, 0);
6224 : nsIFrame* rootFrameParent =
6225 8 : nsLayoutUtils::GetCrossDocParentFrame(rootFrame, &rootFrameOffsetInParent);
6226 8 : if (rootFrameParent) {
6227 0 : nsRect parentScreenRectAppUnits = rootFrameParent->GetScreenRectInAppUnits();
6228 0 : nsPresContext* parentPresContext = rootFrameParent->PresContext();
6229 0 : double parentScale = double(presContext->AppUnitsPerDevPixel())/
6230 0 : parentPresContext->AppUnitsPerDevPixel();
6231 0 : nsPoint rootPt = parentScreenRectAppUnits.TopLeft() + rootFrameOffsetInParent;
6232 0 : rootScreenPos.x = NS_round(parentScale*rootPt.x);
6233 0 : rootScreenPos.y = NS_round(parentScale*rootPt.y);
6234 : } else {
6235 16 : nsCOMPtr<nsIWidget> rootWidget;
6236 8 : presContext->PresShell()->GetViewManager()->GetRootWidget(getter_AddRefs(rootWidget));
6237 8 : if (rootWidget) {
6238 8 : LayoutDeviceIntPoint rootDevPx = rootWidget->WidgetToScreenOffset();
6239 8 : rootScreenPos.x = presContext->DevPixelsToAppUnits(rootDevPx.x);
6240 8 : rootScreenPos.y = presContext->DevPixelsToAppUnits(rootDevPx.y);
6241 : }
6242 : }
6243 :
6244 8 : return nsRect(rootScreenPos + GetOffsetTo(rootFrame), GetSize());
6245 : }
6246 :
6247 : // Returns the offset from this frame to the closest geometric parent that
6248 : // has a view. Also returns the containing view or null in case of error
6249 : void
6250 0 : nsIFrame::GetOffsetFromView(nsPoint& aOffset, nsView** aView) const
6251 : {
6252 0 : NS_PRECONDITION(nullptr != aView, "null OUT parameter pointer");
6253 0 : nsIFrame* frame = const_cast<nsIFrame*>(this);
6254 :
6255 0 : *aView = nullptr;
6256 0 : aOffset.MoveTo(0, 0);
6257 0 : do {
6258 0 : aOffset += frame->GetPosition();
6259 0 : frame = frame->GetParent();
6260 0 : } while (frame && !frame->HasView());
6261 :
6262 0 : if (frame) {
6263 0 : *aView = frame->GetView();
6264 : }
6265 0 : }
6266 :
6267 : nsIWidget*
6268 913 : nsIFrame::GetNearestWidget() const
6269 : {
6270 913 : return GetClosestView()->GetNearestWidget(nullptr);
6271 : }
6272 :
6273 : nsIWidget*
6274 0 : nsIFrame::GetNearestWidget(nsPoint& aOffset) const
6275 : {
6276 0 : nsPoint offsetToView;
6277 0 : nsPoint offsetToWidget;
6278 : nsIWidget* widget =
6279 0 : GetClosestView(&offsetToView)->GetNearestWidget(&offsetToWidget);
6280 0 : aOffset = offsetToView + offsetToWidget;
6281 0 : return widget;
6282 : }
6283 :
6284 : nsIFrame*
6285 5137 : nsIFrame::GetFlattenedTreeParentPrimaryFrame() const
6286 : {
6287 5137 : if (!GetContent()) {
6288 588 : return nullptr;
6289 : }
6290 4549 : nsIContent* parent = GetContent()->GetFlattenedTreeParent();
6291 4549 : return parent ? parent->GetPrimaryFrame() : nullptr;
6292 : }
6293 :
6294 : Matrix4x4
6295 593 : nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
6296 : nsIFrame** aOutAncestor,
6297 : bool aInCSSUnits)
6298 : {
6299 593 : NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
6300 :
6301 : /* If we're transformed, we want to hand back the combination
6302 : * transform/translate matrix that will apply our current transform, then
6303 : * shift us to our parent.
6304 : */
6305 593 : if (IsTransformed()) {
6306 : /* Compute the delta to the parent, which we need because we are converting
6307 : * coordinates to our parent.
6308 : */
6309 0 : NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
6310 : "Cannot transform the viewport frame!");
6311 0 : int32_t scaleFactor = (aInCSSUnits ? PresContext()->AppUnitsPerCSSPixel()
6312 0 : : PresContext()->AppUnitsPerDevPixel());
6313 :
6314 : Matrix4x4 result = nsDisplayTransform::GetResultingTransformMatrix(this,
6315 0 : nsPoint(0,0), scaleFactor,
6316 : nsDisplayTransform::INCLUDE_PERSPECTIVE|nsDisplayTransform::OFFSET_BY_ORIGIN,
6317 0 : nullptr);
6318 0 : *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
6319 0 : nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
6320 : /* Combine the raw transform with a translation to our parent. */
6321 : result.PostTranslate(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
6322 : NSAppUnitsToFloatPixels(delta.y, scaleFactor),
6323 0 : 0.0f);
6324 :
6325 0 : return result;
6326 : }
6327 :
6328 593 : if (nsLayoutUtils::IsPopup(this) && IsListControlFrame()) {
6329 0 : nsPresContext* presContext = PresContext();
6330 0 : nsIFrame* docRootFrame = presContext->PresShell()->GetRootFrame();
6331 :
6332 : // Compute a matrix that transforms from the popup widget to the toplevel
6333 : // widget. We use the widgets because they're the simplest and most
6334 : // accurate approach --- this should work no matter how the widget position
6335 : // was chosen.
6336 0 : nsIWidget* widget = GetView()->GetWidget();
6337 0 : nsPresContext* rootPresContext = PresContext()->GetRootPresContext();
6338 : // Maybe the widget hasn't been created yet? Popups without widgets are
6339 : // treated as regular frames. That should work since they'll be rendered
6340 : // as part of the page if they're rendered at all.
6341 0 : if (widget && rootPresContext) {
6342 0 : nsIWidget* toplevel = rootPresContext->GetNearestWidget();
6343 0 : if (toplevel) {
6344 0 : LayoutDeviceIntRect screenBounds = widget->GetClientBounds();
6345 0 : LayoutDeviceIntRect toplevelScreenBounds = toplevel->GetClientBounds();
6346 : LayoutDeviceIntPoint translation =
6347 0 : screenBounds.TopLeft() - toplevelScreenBounds.TopLeft();
6348 :
6349 0 : Matrix4x4 transformToTop;
6350 0 : transformToTop._41 = translation.x;
6351 0 : transformToTop._42 = translation.y;
6352 :
6353 0 : *aOutAncestor = docRootFrame;
6354 : Matrix4x4 docRootTransformToTop =
6355 0 : nsLayoutUtils::GetTransformToAncestor(docRootFrame, nullptr);
6356 0 : if (docRootTransformToTop.IsSingular()) {
6357 0 : NS_WARNING("Containing document is invisible, we can't compute a valid transform");
6358 : } else {
6359 0 : docRootTransformToTop.Invert();
6360 0 : return transformToTop * docRootTransformToTop;
6361 : }
6362 : }
6363 : }
6364 : }
6365 :
6366 593 : *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
6367 :
6368 : /* Otherwise, we're not transformed. In that case, we'll walk up the frame
6369 : * tree until we either hit the root frame or something that may be
6370 : * transformed. We'll then change coordinates into that frame, since we're
6371 : * guaranteed that nothing in-between can be transformed. First, however,
6372 : * we have to check to see if we have a parent. If not, we'll set the
6373 : * outparam to null (indicating that there's nothing left) and will hand back
6374 : * the identity matrix.
6375 : */
6376 593 : if (!*aOutAncestor)
6377 0 : return Matrix4x4();
6378 :
6379 : /* Keep iterating while the frame can't possibly be transformed. */
6380 13067 : while (!(*aOutAncestor)->IsTransformed() &&
6381 6830 : !nsLayoutUtils::IsPopup(*aOutAncestor) &&
6382 3415 : *aOutAncestor != aStopAtAncestor) {
6383 : /* If no parent, stop iterating. Otherwise, update the ancestor. */
6384 2822 : nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
6385 2822 : if (!parent)
6386 0 : break;
6387 :
6388 2822 : *aOutAncestor = parent;
6389 : }
6390 :
6391 593 : NS_ASSERTION(*aOutAncestor, "Somehow ended up with a null ancestor...?");
6392 :
6393 : /* Translate from this frame to our ancestor, if it exists. That's the
6394 : * entire transform, so we're done.
6395 : */
6396 593 : nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
6397 1186 : int32_t scaleFactor = (aInCSSUnits ? PresContext()->AppUnitsPerCSSPixel()
6398 1186 : : PresContext()->AppUnitsPerDevPixel());
6399 : return Matrix4x4::Translation(NSAppUnitsToFloatPixels(delta.x, scaleFactor),
6400 : NSAppUnitsToFloatPixels(delta.y, scaleFactor),
6401 593 : 0.0f);
6402 : }
6403 :
6404 212 : static void InvalidateRenderingObservers(nsIFrame* aFrame)
6405 : {
6406 212 : nsSVGEffects::InvalidateDirectRenderingObservers(aFrame);
6407 212 : nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
6408 212 : nsIFrame* parent = aFrame;
6409 1911 : while (parent != displayRoot &&
6410 1370 : (parent = nsLayoutUtils::GetCrossDocParentFrame(parent)) &&
6411 617 : !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
6412 541 : nsSVGEffects::InvalidateDirectRenderingObservers(parent);
6413 : }
6414 212 : }
6415 :
6416 : void
6417 365 : SchedulePaintInternal(nsIFrame* aFrame, nsIFrame::PaintType aType = nsIFrame::PAINT_DEFAULT)
6418 : {
6419 365 : nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(aFrame);
6420 365 : nsPresContext* pres = displayRoot->PresContext()->GetRootPresContext();
6421 :
6422 : // No need to schedule a paint for an external document since they aren't
6423 : // painted directly.
6424 365 : if (!pres || (pres->Document() && pres->Document()->IsResourceDoc())) {
6425 144 : return;
6426 : }
6427 221 : if (!pres->GetContainerWeak()) {
6428 0 : NS_WARNING("Shouldn't call SchedulePaint in a detached pres context");
6429 0 : return;
6430 : }
6431 :
6432 442 : pres->PresShell()->ScheduleViewManagerFlush(aType == nsIFrame::PAINT_DELAYED_COMPRESS ?
6433 : nsIPresShell::PAINT_DELAYED_COMPRESS :
6434 442 : nsIPresShell::PAINT_DEFAULT);
6435 :
6436 221 : if (aType == nsIFrame::PAINT_DELAYED_COMPRESS) {
6437 11 : return;
6438 : }
6439 :
6440 210 : if (aType == nsIFrame::PAINT_DEFAULT) {
6441 201 : displayRoot->AddStateBits(NS_FRAME_UPDATE_LAYER_TREE);
6442 : }
6443 : }
6444 :
6445 1255 : static void InvalidateFrameInternal(nsIFrame *aFrame, bool aHasDisplayItem = true)
6446 : {
6447 1255 : if (aHasDisplayItem) {
6448 1247 : aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT);
6449 : }
6450 1255 : nsSVGEffects::InvalidateDirectRenderingObservers(aFrame);
6451 1255 : bool needsSchedulePaint = false;
6452 1255 : if (nsLayoutUtils::IsPopup(aFrame)) {
6453 46 : needsSchedulePaint = true;
6454 : } else {
6455 1209 : nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
6456 2813 : while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
6457 802 : if (aHasDisplayItem && !parent->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) {
6458 793 : parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
6459 : }
6460 802 : nsSVGEffects::InvalidateDirectRenderingObservers(parent);
6461 :
6462 : // If we're inside a popup, then we need to make sure that we
6463 : // call schedule paint so that the NS_FRAME_UPDATE_LAYER_TREE
6464 : // flag gets added to the popup display root frame.
6465 802 : if (nsLayoutUtils::IsPopup(parent)) {
6466 0 : needsSchedulePaint = true;
6467 0 : break;
6468 : }
6469 802 : parent = nsLayoutUtils::GetCrossDocParentFrame(parent);
6470 : }
6471 1209 : if (!parent) {
6472 144 : needsSchedulePaint = true;
6473 : }
6474 : }
6475 1255 : if (!aHasDisplayItem) {
6476 8 : return;
6477 : }
6478 1247 : if (needsSchedulePaint) {
6479 190 : SchedulePaintInternal(aFrame);
6480 : }
6481 1247 : if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
6482 0 : aFrame->DeleteProperty(nsIFrame::InvalidationRect());
6483 0 : aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT);
6484 : }
6485 : }
6486 :
6487 : void
6488 1038 : nsIFrame::InvalidateFrameSubtree(uint32_t aDisplayItemKey)
6489 : {
6490 : bool hasDisplayItem =
6491 1038 : !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
6492 1038 : InvalidateFrame(aDisplayItemKey);
6493 :
6494 1038 : if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT) || !hasDisplayItem) {
6495 428 : return;
6496 : }
6497 :
6498 610 : AddStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
6499 :
6500 1220 : AutoTArray<nsIFrame::ChildList,4> childListArray;
6501 610 : GetCrossDocChildLists(&childListArray);
6502 :
6503 610 : nsIFrame::ChildListArrayIterator lists(childListArray);
6504 1320 : for (; !lists.IsDone(); lists.Next()) {
6505 355 : nsFrameList::Enumerator childFrames(lists.CurrentList());
6506 1421 : for (; !childFrames.AtEnd(); childFrames.Next()) {
6507 533 : childFrames.get()->InvalidateFrameSubtree();
6508 : }
6509 : }
6510 : }
6511 :
6512 : void
6513 1720 : nsIFrame::ClearInvalidationStateBits()
6514 : {
6515 1720 : if (HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
6516 1432 : AutoTArray<nsIFrame::ChildList,4> childListArray;
6517 716 : GetCrossDocChildLists(&childListArray);
6518 :
6519 716 : nsIFrame::ChildListArrayIterator lists(childListArray);
6520 2242 : for (; !lists.IsDone(); lists.Next()) {
6521 763 : nsFrameList::Enumerator childFrames(lists.CurrentList());
6522 4115 : for (; !childFrames.AtEnd(); childFrames.Next()) {
6523 1676 : childFrames.get()->ClearInvalidationStateBits();
6524 : }
6525 : }
6526 : }
6527 :
6528 1720 : RemoveStateBits(NS_FRAME_NEEDS_PAINT |
6529 : NS_FRAME_DESCENDANT_NEEDS_PAINT |
6530 1720 : NS_FRAME_ALL_DESCENDANTS_NEED_PAINT);
6531 1720 : }
6532 :
6533 : void
6534 1255 : nsIFrame::InvalidateFrame(uint32_t aDisplayItemKey)
6535 : {
6536 : bool hasDisplayItem =
6537 1255 : !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
6538 1255 : InvalidateFrameInternal(this, hasDisplayItem);
6539 1255 : }
6540 :
6541 : void
6542 0 : nsIFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey)
6543 : {
6544 : bool hasDisplayItem =
6545 0 : !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey);
6546 0 : bool alreadyInvalid = false;
6547 0 : if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
6548 0 : InvalidateFrameInternal(this, hasDisplayItem);
6549 : } else {
6550 0 : alreadyInvalid = true;
6551 : }
6552 :
6553 0 : if (!hasDisplayItem) {
6554 0 : return;
6555 : }
6556 :
6557 : nsRect* rect;
6558 0 : if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
6559 0 : rect = GetProperty(InvalidationRect());
6560 0 : MOZ_ASSERT(rect);
6561 : } else {
6562 0 : if (alreadyInvalid) {
6563 0 : return;
6564 : }
6565 0 : rect = new nsRect();
6566 0 : AddProperty(InvalidationRect(), rect);
6567 0 : AddStateBits(NS_FRAME_HAS_INVALID_RECT);
6568 : }
6569 :
6570 0 : *rect = rect->Union(aRect);
6571 : }
6572 :
6573 : /*static*/ uint8_t nsIFrame::sLayerIsPrerenderedDataKey;
6574 :
6575 : static bool
6576 0 : DoesLayerHaveOutOfDateFrameMetrics(Layer* aLayer)
6577 : {
6578 0 : for (uint32_t i = 0; i < aLayer->GetScrollMetadataCount(); i++) {
6579 0 : const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
6580 0 : if (!metrics.IsScrollable()) {
6581 0 : continue;
6582 : }
6583 : nsIScrollableFrame* scrollableFrame =
6584 0 : nsLayoutUtils::FindScrollableFrameFor(metrics.GetScrollId());
6585 0 : if (!scrollableFrame) {
6586 : // This shouldn't happen, so let's do the safe thing and trigger a full
6587 : // paint if it does.
6588 0 : return true;
6589 : }
6590 0 : nsPoint scrollPosition = scrollableFrame->GetScrollPosition();
6591 0 : if (metrics.GetScrollOffset() != CSSPoint::FromAppUnits(scrollPosition)) {
6592 0 : return true;
6593 : }
6594 : }
6595 0 : return false;
6596 : }
6597 :
6598 : static bool
6599 0 : DoesLayerOrAncestorsHaveOutOfDateFrameMetrics(Layer* aLayer)
6600 : {
6601 0 : for (Layer* layer = aLayer; layer; layer = layer->GetParent()) {
6602 0 : if (DoesLayerHaveOutOfDateFrameMetrics(layer)) {
6603 0 : return true;
6604 : }
6605 : }
6606 0 : return false;
6607 : }
6608 :
6609 : bool
6610 0 : nsIFrame::TryUpdateTransformOnly(Layer** aLayerResult)
6611 : {
6612 : Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
6613 0 : this, nsDisplayItem::TYPE_TRANSFORM);
6614 0 : if (!layer || !layer->HasUserData(LayerIsPrerenderedDataKey())) {
6615 : // If this layer isn't prerendered or we clip composites to our OS
6616 : // window, then we can't correctly optimize to an empty
6617 : // transaction in general.
6618 0 : return false;
6619 : }
6620 :
6621 0 : if (DoesLayerOrAncestorsHaveOutOfDateFrameMetrics(layer)) {
6622 : // At least one scroll frame that can affect the position of this layer
6623 : // has changed its scroll offset since the last paint. Schedule a full
6624 : // paint to make sure that this layer's transform and all the frame
6625 : // metrics that affect it are in sync.
6626 0 : return false;
6627 : }
6628 :
6629 0 : gfx::Matrix4x4 transform3d;
6630 0 : if (!nsLayoutUtils::GetLayerTransformForFrame(this, &transform3d)) {
6631 : // We're not able to compute a layer transform that we know would
6632 : // be used at the next layers transaction, so we can't only update
6633 : // the transform and will need to schedule an invalidating paint.
6634 0 : return false;
6635 : }
6636 0 : gfx::Matrix transform;
6637 0 : gfx::Matrix previousTransform;
6638 : // FIXME/bug 796690 and 796705: in general, changes to 3D
6639 : // transforms, or transform changes to properties other than
6640 : // translation, may lead us to choose a different rendering
6641 : // resolution for our layer. So if the transform is 3D or has a
6642 : // non-translation change, bail and schedule an invalidating paint.
6643 : // (We can often do better than this, for example for scale-down
6644 : // changes.)
6645 : static const gfx::Float kError = 0.0001f;
6646 0 : if (!transform3d.Is2D(&transform) ||
6647 0 : !layer->GetBaseTransform().Is2D(&previousTransform) ||
6648 0 : !gfx::FuzzyEqual(transform._11, previousTransform._11, kError) ||
6649 0 : !gfx::FuzzyEqual(transform._22, previousTransform._22, kError) ||
6650 0 : !gfx::FuzzyEqual(transform._21, previousTransform._21, kError) ||
6651 0 : !gfx::FuzzyEqual(transform._12, previousTransform._12, kError)) {
6652 0 : return false;
6653 : }
6654 0 : layer->SetBaseTransformForNextTransaction(transform3d);
6655 0 : *aLayerResult = layer;
6656 0 : return true;
6657 : }
6658 :
6659 : bool
6660 1165 : nsIFrame::IsInvalid(nsRect& aRect)
6661 : {
6662 1165 : if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) {
6663 1082 : return false;
6664 : }
6665 :
6666 83 : if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) {
6667 0 : nsRect* rect = GetProperty(InvalidationRect());
6668 0 : NS_ASSERTION(rect, "Must have an invalid rect if NS_FRAME_HAS_INVALID_RECT is set!");
6669 0 : aRect = *rect;
6670 : } else {
6671 83 : aRect.SetEmpty();
6672 : }
6673 83 : return true;
6674 : }
6675 :
6676 : void
6677 174 : nsIFrame::SchedulePaint(PaintType aType)
6678 : {
6679 174 : InvalidateRenderingObservers(this);
6680 174 : SchedulePaintInternal(this, aType);
6681 174 : }
6682 :
6683 : Layer*
6684 38 : nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey,
6685 : const nsIntRect* aDamageRect,
6686 : const nsRect* aFrameDamageRect,
6687 : uint32_t aFlags /* = 0 */)
6688 : {
6689 38 : NS_ASSERTION(aDisplayItemKey > 0, "Need a key");
6690 :
6691 38 : Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey);
6692 :
6693 38 : InvalidateRenderingObservers(this);
6694 :
6695 : // If the layer is being updated asynchronously, and it's being forwarded
6696 : // to a compositor, then we don't need to invalidate.
6697 38 : if ((aFlags & UPDATE_IS_ASYNC) && layer && layer->SupportsAsyncUpdate()) {
6698 0 : return layer;
6699 : }
6700 :
6701 38 : if (!layer) {
6702 37 : if (aFrameDamageRect && aFrameDamageRect->IsEmpty()) {
6703 0 : return nullptr;
6704 : }
6705 :
6706 : // Plugins can transition from not rendering anything to rendering,
6707 : // and still only call this. So always invalidate, with specifying
6708 : // the display item type just in case.
6709 : //
6710 : // In the bug 930056, dialer app startup but not shown on the
6711 : // screen because sometimes we don't have any retainned data
6712 : // for remote type displayitem and thus Repaint event is not
6713 : // triggered. So, always invalidate here as well.
6714 37 : uint32_t displayItemKey = aDisplayItemKey;
6715 37 : if (aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN ||
6716 : aDisplayItemKey == nsDisplayItem::TYPE_REMOTE) {
6717 0 : displayItemKey = 0;
6718 : }
6719 :
6720 37 : if (aFrameDamageRect) {
6721 0 : InvalidateFrameWithRect(*aFrameDamageRect, displayItemKey);
6722 : } else {
6723 37 : InvalidateFrame(displayItemKey);
6724 : }
6725 :
6726 37 : return nullptr;
6727 : }
6728 :
6729 1 : if (aDamageRect && aDamageRect->IsEmpty()) {
6730 0 : return layer;
6731 : }
6732 :
6733 1 : if (aDamageRect) {
6734 0 : layer->AddInvalidRect(*aDamageRect);
6735 : } else {
6736 1 : layer->SetInvalidRectToVisibleRegion();
6737 : }
6738 :
6739 1 : SchedulePaintInternal(this, PAINT_COMPOSITE_ONLY);
6740 1 : return layer;
6741 : }
6742 :
6743 : static nsRect
6744 1710 : ComputeEffectsRect(nsIFrame* aFrame, const nsRect& aOverflowRect,
6745 : const nsSize& aNewSize)
6746 : {
6747 1710 : nsRect r = aOverflowRect;
6748 :
6749 1710 : if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
6750 : // For SVG frames, we only need to account for filters.
6751 : // TODO: We could also take account of clipPath and mask to reduce the
6752 : // visual overflow, but that's not essential.
6753 180 : if (aFrame->StyleEffects()->HasFilters()) {
6754 : aFrame->SetProperty
6755 0 : (nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
6756 0 : r = nsSVGUtils::GetPostFilterVisualOverflowRect(aFrame, aOverflowRect);
6757 : }
6758 180 : return r;
6759 : }
6760 :
6761 : // box-shadow
6762 1530 : r.UnionRect(r, nsLayoutUtils::GetBoxShadowRectForFrame(aFrame, aNewSize));
6763 :
6764 : // border-image-outset.
6765 : // We need to include border-image-outset because it can cause the
6766 : // border image to be drawn beyond the border box.
6767 :
6768 : // (1) It's important we not check whether there's a border-image
6769 : // since the style hint for a change in border image doesn't cause
6770 : // reflow, and that's probably more important than optimizing the
6771 : // overflow areas for the silly case of border-image-outset without
6772 : // border-image
6773 : // (2) It's important that we not check whether the border-image
6774 : // is actually loaded, since that would require us to reflow when
6775 : // the image loads.
6776 1530 : const nsStyleBorder* styleBorder = aFrame->StyleBorder();
6777 1530 : nsMargin outsetMargin = styleBorder->GetImageOutset();
6778 :
6779 1530 : if (outsetMargin != nsMargin(0, 0, 0, 0)) {
6780 0 : nsRect outsetRect(nsPoint(0, 0), aNewSize);
6781 0 : outsetRect.Inflate(outsetMargin);
6782 0 : r.UnionRect(r, outsetRect);
6783 : }
6784 :
6785 : // Note that we don't remove the outlineInnerRect if a frame loses outline
6786 : // style. That would require an extra property lookup for every frame,
6787 : // or a new frame state bit to track whether a property had been stored,
6788 : // or something like that. It's not worth doing that here. At most it's
6789 : // only one heap-allocated rect per frame and it will be cleaned up when
6790 : // the frame dies.
6791 :
6792 1530 : if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
6793 : aFrame->SetProperty
6794 1 : (nsIFrame::PreEffectsBBoxProperty(), new nsRect(r));
6795 1 : r = nsSVGIntegrationUtils::ComputePostEffectsVisualOverflowRect(aFrame, r);
6796 : }
6797 :
6798 1530 : return r;
6799 : }
6800 :
6801 : void
6802 0 : nsIFrame::MovePositionBy(const nsPoint& aTranslation)
6803 : {
6804 0 : nsPoint position = GetNormalPosition() + aTranslation;
6805 :
6806 0 : const nsMargin* computedOffsets = nullptr;
6807 0 : if (IsRelativelyPositioned()) {
6808 0 : computedOffsets = GetProperty(nsIFrame::ComputedOffsetProperty());
6809 : }
6810 0 : ReflowInput::ApplyRelativePositioning(this, computedOffsets ?
6811 : *computedOffsets : nsMargin(),
6812 0 : &position);
6813 0 : SetPosition(position);
6814 0 : }
6815 :
6816 : nsRect
6817 0 : nsIFrame::GetNormalRect() const
6818 : {
6819 : // It might be faster to first check
6820 : // StyleDisplay()->IsRelativelyPositionedStyle().
6821 0 : nsPoint* normalPosition = GetProperty(NormalPositionProperty());
6822 0 : if (normalPosition) {
6823 0 : return nsRect(*normalPosition, GetSize());
6824 : }
6825 0 : return GetRect();
6826 : }
6827 :
6828 : nsPoint
6829 855 : nsIFrame::GetPositionIgnoringScrolling()
6830 : {
6831 2565 : return GetParent() ? GetParent()->GetPositionOfChildIgnoringScrolling(this)
6832 2565 : : GetPosition();
6833 : }
6834 :
6835 : nsRect
6836 6072 : nsIFrame::GetOverflowRect(nsOverflowType aType) const
6837 : {
6838 6072 : MOZ_ASSERT(aType == eVisualOverflow || aType == eScrollableOverflow,
6839 : "unexpected type");
6840 :
6841 : // Note that in some cases the overflow area might not have been
6842 : // updated (yet) to reflect any outline set on the frame or the area
6843 : // of child frames. That's OK because any reflow that updates these
6844 : // areas will invalidate the appropriate area, so any (mis)uses of
6845 : // this method will be fixed up.
6846 :
6847 6072 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
6848 : // there is an overflow rect, and it's not stored as deltas but as
6849 : // a separately-allocated rect
6850 1041 : return GetOverflowAreasProperty()->Overflow(aType);
6851 : }
6852 :
6853 8812 : if (aType == eVisualOverflow &&
6854 3781 : mOverflow.mType != NS_FRAME_OVERFLOW_NONE) {
6855 0 : return GetVisualOverflowFromDeltas();
6856 : }
6857 :
6858 5031 : return nsRect(nsPoint(0, 0), GetSize());
6859 : }
6860 :
6861 : nsOverflowAreas
6862 1444 : nsIFrame::GetOverflowAreas() const
6863 : {
6864 1444 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
6865 : // there is an overflow rect, and it's not stored as deltas but as
6866 : // a separately-allocated rect
6867 187 : return *GetOverflowAreasProperty();
6868 : }
6869 :
6870 2514 : return nsOverflowAreas(GetVisualOverflowFromDeltas(),
6871 3771 : nsRect(nsPoint(0, 0), GetSize()));
6872 : }
6873 :
6874 : nsOverflowAreas
6875 0 : nsIFrame::GetOverflowAreasRelativeToSelf() const
6876 : {
6877 0 : if (IsTransformed()) {
6878 : nsOverflowAreas* preTransformOverflows =
6879 0 : GetProperty(PreTransformOverflowAreasProperty());
6880 0 : if (preTransformOverflows) {
6881 0 : return nsOverflowAreas(preTransformOverflows->VisualOverflow(),
6882 0 : preTransformOverflows->ScrollableOverflow());
6883 : }
6884 : }
6885 0 : return nsOverflowAreas(GetVisualOverflowRect(),
6886 0 : GetScrollableOverflowRect());
6887 : }
6888 :
6889 : nsRect
6890 270 : nsIFrame::GetScrollableOverflowRectRelativeToParent() const
6891 : {
6892 270 : return GetScrollableOverflowRect() + mRect.TopLeft();
6893 : }
6894 :
6895 : nsRect
6896 6 : nsIFrame::GetVisualOverflowRectRelativeToParent() const
6897 : {
6898 6 : return GetVisualOverflowRect() + mRect.TopLeft();
6899 : }
6900 :
6901 : nsRect
6902 0 : nsIFrame::GetScrollableOverflowRectRelativeToSelf() const
6903 : {
6904 0 : if (IsTransformed()) {
6905 : nsOverflowAreas* preTransformOverflows =
6906 0 : GetProperty(PreTransformOverflowAreasProperty());
6907 0 : if (preTransformOverflows)
6908 0 : return preTransformOverflows->ScrollableOverflow();
6909 : }
6910 0 : return GetScrollableOverflowRect();
6911 : }
6912 :
6913 : nsRect
6914 241 : nsIFrame::GetVisualOverflowRectRelativeToSelf() const
6915 : {
6916 241 : if (IsTransformed()) {
6917 : nsOverflowAreas* preTransformOverflows =
6918 24 : GetProperty(PreTransformOverflowAreasProperty());
6919 24 : if (preTransformOverflows)
6920 24 : return preTransformOverflows->VisualOverflow();
6921 : }
6922 217 : return GetVisualOverflowRect();
6923 : }
6924 :
6925 : nsRect
6926 0 : nsIFrame::GetPreEffectsVisualOverflowRect() const
6927 : {
6928 0 : nsRect* r = GetProperty(nsIFrame::PreEffectsBBoxProperty());
6929 0 : return r ? *r : GetVisualOverflowRectRelativeToSelf();
6930 : }
6931 :
6932 : bool
6933 0 : nsIFrame::UpdateOverflow()
6934 : {
6935 0 : MOZ_ASSERT(FrameMaintainsOverflow(),
6936 : "Non-display SVG do not maintain visual overflow rects");
6937 :
6938 0 : nsRect rect(nsPoint(0, 0), GetSize());
6939 0 : nsOverflowAreas overflowAreas(rect, rect);
6940 :
6941 0 : if (!ComputeCustomOverflow(overflowAreas)) {
6942 0 : return false;
6943 : }
6944 :
6945 0 : UnionChildOverflow(overflowAreas);
6946 :
6947 0 : if (FinishAndStoreOverflow(overflowAreas, GetSize())) {
6948 0 : nsView* view = GetView();
6949 0 : if (view) {
6950 0 : uint32_t flags = GetXULLayoutFlags();
6951 :
6952 0 : if ((flags & NS_FRAME_NO_SIZE_VIEW) == 0) {
6953 : // Make sure the frame's view is properly sized.
6954 0 : nsViewManager* vm = view->GetViewManager();
6955 0 : vm->ResizeView(view, overflowAreas.VisualOverflow(), true);
6956 : }
6957 : }
6958 :
6959 0 : return true;
6960 : }
6961 :
6962 0 : return false;
6963 : }
6964 :
6965 : /* virtual */ bool
6966 0 : nsFrame::ComputeCustomOverflow(nsOverflowAreas& aOverflowAreas)
6967 : {
6968 0 : return true;
6969 : }
6970 :
6971 : /* virtual */ void
6972 0 : nsFrame::UnionChildOverflow(nsOverflowAreas& aOverflowAreas)
6973 : {
6974 0 : if (!DoesClipChildren() &&
6975 0 : !(IsXULCollapsed() && (IsXULBoxFrame() || ::IsXULBoxWrapped(this)))) {
6976 0 : nsLayoutUtils::UnionChildOverflow(this, aOverflowAreas);
6977 : }
6978 0 : }
6979 :
6980 :
6981 : // Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus
6982 : // 4 for the frames above the document's frames:
6983 : // the Viewport, GFXScroll, ScrollPort, and Canvas
6984 : #define MAX_FRAME_DEPTH (MAX_REFLOW_DEPTH+4)
6985 :
6986 : bool
6987 162 : nsFrame::IsFrameTreeTooDeep(const ReflowInput& aReflowInput,
6988 : ReflowOutput& aMetrics,
6989 : nsReflowStatus& aStatus)
6990 : {
6991 162 : if (aReflowInput.mReflowDepth > MAX_FRAME_DEPTH) {
6992 0 : NS_WARNING("frame tree too deep; setting zero size and returning");
6993 0 : mState |= NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
6994 0 : ClearOverflowRects();
6995 0 : aMetrics.ClearSize();
6996 0 : aMetrics.SetBlockStartAscent(0);
6997 0 : aMetrics.mCarriedOutBEndMargin.Zero();
6998 0 : aMetrics.mOverflowAreas.Clear();
6999 :
7000 0 : aStatus.Reset();
7001 0 : if (GetNextInFlow()) {
7002 : // Reflow depth might vary between reflows, so we might have
7003 : // successfully reflowed and split this frame before. If so, we
7004 : // shouldn't delete its continuations.
7005 0 : aStatus.SetIncomplete();
7006 : }
7007 :
7008 0 : return true;
7009 : }
7010 162 : mState &= ~NS_FRAME_TOO_DEEP_IN_FRAME_TREE;
7011 162 : return false;
7012 : }
7013 :
7014 : bool
7015 1678 : nsIFrame::IsBlockWrapper() const
7016 : {
7017 1678 : nsIAtom *pseudoType = StyleContext()->GetPseudo();
7018 3356 : return (pseudoType == nsCSSAnonBoxes::mozBlockInsideInlineWrapper ||
7019 3356 : pseudoType == nsCSSAnonBoxes::buttonContent ||
7020 3356 : pseudoType == nsCSSAnonBoxes::cellContent);
7021 : }
7022 :
7023 : static nsIFrame*
7024 709 : GetNearestBlockContainer(nsIFrame* frame)
7025 : {
7026 : // The block wrappers we use to wrap blocks inside inlines aren't
7027 : // described in the CSS spec. We need to make them not be containing
7028 : // blocks.
7029 : // Since the parent of such a block is either a normal block or
7030 : // another such pseudo, this shouldn't cause anything bad to happen.
7031 : // Also the anonymous blocks inside table cells are not containing blocks.
7032 2127 : while (frame->IsFrameOfType(nsIFrame::eLineParticipant) ||
7033 1418 : frame->IsBlockWrapper() ||
7034 : // Table rows are not containing blocks either
7035 709 : frame->IsTableRowFrame()) {
7036 0 : frame = frame->GetParent();
7037 0 : NS_ASSERTION(frame, "How come we got to the root frame without seeing a containing block?");
7038 : }
7039 709 : return frame;
7040 : }
7041 :
7042 : nsIFrame*
7043 786 : nsIFrame::GetContainingBlock(uint32_t aFlags,
7044 : const nsStyleDisplay* aStyleDisplay) const
7045 : {
7046 786 : MOZ_ASSERT(aStyleDisplay == StyleDisplay());
7047 786 : if (!GetParent()) {
7048 0 : return nullptr;
7049 : }
7050 : // MathML frames might have absolute positioning style, but they would
7051 : // still be in-flow. So we have to check to make sure that the frame
7052 : // is really out-of-flow too.
7053 : nsIFrame* f;
7054 863 : if (IsAbsolutelyPositioned(aStyleDisplay) &&
7055 77 : (GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
7056 77 : f = GetParent(); // the parent is always the containing block
7057 : } else {
7058 709 : f = GetNearestBlockContainer(GetParent());
7059 : }
7060 :
7061 1128 : if (aFlags & SKIP_SCROLLED_FRAME && f &&
7062 342 : f->StyleContext()->GetPseudo() == nsCSSAnonBoxes::scrolledContent) {
7063 12 : f = f->GetParent();
7064 : }
7065 786 : return f;
7066 : }
7067 :
7068 : #ifdef DEBUG_FRAME_DUMP
7069 :
7070 0 : int32_t nsFrame::ContentIndexInContainer(const nsIFrame* aFrame)
7071 : {
7072 0 : int32_t result = -1;
7073 :
7074 0 : nsIContent* content = aFrame->GetContent();
7075 0 : if (content) {
7076 0 : nsIContent* parentContent = content->GetParent();
7077 0 : if (parentContent) {
7078 0 : result = parentContent->IndexOf(content);
7079 : }
7080 : }
7081 :
7082 0 : return result;
7083 : }
7084 :
7085 : /**
7086 : * List a frame tree to stderr. Meant to be called from gdb.
7087 : */
7088 : void
7089 0 : DebugListFrameTree(nsIFrame* aFrame)
7090 : {
7091 0 : ((nsFrame*)aFrame)->List(stderr);
7092 0 : }
7093 :
7094 : void
7095 0 : nsIFrame::ListTag(nsACString& aTo) const
7096 : {
7097 0 : ListTag(aTo, this);
7098 0 : }
7099 :
7100 : /* static */
7101 : void
7102 0 : nsIFrame::ListTag(nsACString& aTo, const nsIFrame* aFrame) {
7103 0 : nsAutoString tmp;
7104 0 : aFrame->GetFrameName(tmp);
7105 0 : aTo += NS_ConvertUTF16toUTF8(tmp).get();
7106 0 : aTo += nsPrintfCString("@%p", static_cast<const void*>(aFrame));
7107 0 : }
7108 :
7109 : // Debugging
7110 : void
7111 0 : nsIFrame::ListGeneric(nsACString& aTo, const char* aPrefix, uint32_t aFlags) const
7112 : {
7113 0 : aTo =+ aPrefix;
7114 0 : ListTag(aTo);
7115 0 : if (HasView()) {
7116 0 : aTo += nsPrintfCString(" [view=%p]", static_cast<void*>(GetView()));
7117 : }
7118 0 : if (GetNextSibling()) {
7119 0 : aTo += nsPrintfCString(" next=%p", static_cast<void*>(GetNextSibling()));
7120 : }
7121 0 : if (GetPrevContinuation()) {
7122 0 : bool fluid = GetPrevInFlow() == GetPrevContinuation();
7123 0 : aTo += nsPrintfCString(" prev-%s=%p", fluid?"in-flow":"continuation",
7124 0 : static_cast<void*>(GetPrevContinuation()));
7125 : }
7126 0 : if (GetNextContinuation()) {
7127 0 : bool fluid = GetNextInFlow() == GetNextContinuation();
7128 0 : aTo += nsPrintfCString(" next-%s=%p", fluid?"in-flow":"continuation",
7129 0 : static_cast<void*>(GetNextContinuation()));
7130 : }
7131 0 : void* IBsibling = GetProperty(IBSplitSibling());
7132 0 : if (IBsibling) {
7133 0 : aTo += nsPrintfCString(" IBSplitSibling=%p", IBsibling);
7134 : }
7135 0 : void* IBprevsibling = GetProperty(IBSplitPrevSibling());
7136 0 : if (IBprevsibling) {
7137 0 : aTo += nsPrintfCString(" IBSplitPrevSibling=%p", IBprevsibling);
7138 : }
7139 0 : aTo += nsPrintfCString(" {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
7140 :
7141 0 : mozilla::WritingMode wm = GetWritingMode();
7142 0 : if (wm.IsVertical() || !wm.IsBidiLTR()) {
7143 0 : aTo += nsPrintfCString(" wm=%s: logical size={%d,%d}", wm.DebugString(),
7144 0 : ISize(), BSize());
7145 : }
7146 :
7147 0 : nsIFrame* parent = GetParent();
7148 0 : if (parent) {
7149 0 : WritingMode pWM = parent->GetWritingMode();
7150 0 : if (pWM.IsVertical() || !pWM.IsBidiLTR()) {
7151 0 : nsSize containerSize = parent->mRect.Size();
7152 0 : LogicalRect lr(pWM, mRect, containerSize);
7153 0 : aTo += nsPrintfCString(" parent wm=%s, cs={%d,%d}, "
7154 : " logicalRect={%d,%d,%d,%d}",
7155 : pWM.DebugString(),
7156 : containerSize.width, containerSize.height,
7157 0 : lr.IStart(pWM), lr.BStart(pWM),
7158 0 : lr.ISize(pWM), lr.BSize(pWM));
7159 : }
7160 : }
7161 0 : nsIFrame* f = const_cast<nsIFrame*>(this);
7162 0 : if (f->HasOverflowAreas()) {
7163 0 : nsRect vo = f->GetVisualOverflowRect();
7164 0 : if (!vo.IsEqualEdges(mRect)) {
7165 0 : aTo += nsPrintfCString(" vis-overflow=%d,%d,%d,%d", vo.x, vo.y, vo.width, vo.height);
7166 : }
7167 0 : nsRect so = f->GetScrollableOverflowRect();
7168 0 : if (!so.IsEqualEdges(mRect)) {
7169 0 : aTo += nsPrintfCString(" scr-overflow=%d,%d,%d,%d", so.x, so.y, so.width, so.height);
7170 : }
7171 : }
7172 0 : if (0 != mState) {
7173 0 : aTo += nsPrintfCString(" [state=%016llx]", (unsigned long long)mState);
7174 : }
7175 0 : if (HasProperty(BidiDataProperty())) {
7176 0 : FrameBidiData bidi = GetBidiData();
7177 0 : aTo += nsPrintfCString(" bidi(%d,%d,%d)", bidi.baseLevel,
7178 0 : bidi.embeddingLevel, bidi.precedingControl);
7179 : }
7180 0 : if (IsTransformed()) {
7181 0 : aTo += nsPrintfCString(" transformed");
7182 : }
7183 0 : if (ChildrenHavePerspective()) {
7184 0 : aTo += nsPrintfCString(" perspective");
7185 : }
7186 0 : if (Extend3DContext()) {
7187 0 : aTo += nsPrintfCString(" extend-3d");
7188 : }
7189 0 : if (Combines3DTransformWithAncestors()) {
7190 0 : aTo += nsPrintfCString(" combines-3d-transform-with-ancestors");
7191 : }
7192 0 : if (mContent) {
7193 0 : aTo += nsPrintfCString(" [content=%p]", static_cast<void*>(mContent));
7194 : }
7195 0 : aTo += nsPrintfCString(" [sc=%p", static_cast<void*>(mStyleContext));
7196 0 : if (mStyleContext) {
7197 0 : nsIAtom* pseudoTag = mStyleContext->GetPseudo();
7198 0 : if (pseudoTag) {
7199 0 : nsAutoString atomString;
7200 0 : pseudoTag->ToString(atomString);
7201 0 : aTo += nsPrintfCString("%s", NS_LossyConvertUTF16toASCII(atomString).get());
7202 : }
7203 0 : if (mStyleContext->IsGecko()) {
7204 0 : if (!mStyleContext->GetParent() ||
7205 0 : (GetParent() && GetParent()->StyleContext() != mStyleContext->GetParent())) {
7206 0 : aTo += nsPrintfCString("^%p", mStyleContext->GetParent());
7207 0 : if (mStyleContext->GetParent()) {
7208 0 : aTo += nsPrintfCString("^%p", mStyleContext->GetParent()->GetParent());
7209 0 : if (mStyleContext->GetParent()->GetParent()) {
7210 0 : aTo += nsPrintfCString("^%p", mStyleContext->GetParent()->GetParent()->GetParent());
7211 : }
7212 : }
7213 : }
7214 : }
7215 : }
7216 0 : aTo += "]";
7217 0 : }
7218 :
7219 : void
7220 0 : nsIFrame::List(FILE* out, const char* aPrefix, uint32_t aFlags) const
7221 : {
7222 0 : nsCString str;
7223 0 : ListGeneric(str, aPrefix, aFlags);
7224 0 : fprintf_stderr(out, "%s\n", str.get());
7225 0 : }
7226 :
7227 : nsresult
7228 0 : nsFrame::GetFrameName(nsAString& aResult) const
7229 : {
7230 0 : return MakeFrameName(NS_LITERAL_STRING("Frame"), aResult);
7231 : }
7232 :
7233 : nsresult
7234 0 : nsFrame::MakeFrameName(const nsAString& aType, nsAString& aResult) const
7235 : {
7236 0 : aResult = aType;
7237 0 : if (mContent && !mContent->IsNodeOfType(nsINode::eTEXT)) {
7238 0 : nsAutoString buf;
7239 0 : mContent->NodeInfo()->NameAtom()->ToString(buf);
7240 0 : if (IsSubDocumentFrame()) {
7241 0 : nsAutoString src;
7242 0 : mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::src, src);
7243 0 : buf.AppendLiteral(" src=");
7244 0 : buf.Append(src);
7245 : }
7246 0 : aResult.Append('(');
7247 0 : aResult.Append(buf);
7248 0 : aResult.Append(')');
7249 : }
7250 : char buf[40];
7251 0 : SprintfLiteral(buf, "(%d)", ContentIndexInContainer(this));
7252 0 : AppendASCIItoUTF16(buf, aResult);
7253 0 : return NS_OK;
7254 : }
7255 :
7256 : void
7257 0 : nsIFrame::DumpFrameTree() const
7258 : {
7259 0 : RootFrameList(PresContext(), stderr);
7260 0 : }
7261 :
7262 : void
7263 0 : nsIFrame::DumpFrameTreeLimited() const
7264 : {
7265 0 : List(stderr);
7266 0 : }
7267 :
7268 : void
7269 0 : nsIFrame::RootFrameList(nsPresContext* aPresContext, FILE* out, const char* aPrefix)
7270 : {
7271 0 : if (!aPresContext || !out)
7272 0 : return;
7273 :
7274 0 : nsIPresShell *shell = aPresContext->GetPresShell();
7275 0 : if (shell) {
7276 0 : nsIFrame* frame = shell->FrameManager()->GetRootFrame();
7277 0 : if(frame) {
7278 0 : frame->List(out, aPrefix);
7279 : }
7280 : }
7281 : }
7282 : #endif
7283 :
7284 : #ifdef DEBUG
7285 : nsFrameState
7286 0 : nsFrame::GetDebugStateBits() const
7287 : {
7288 : // We'll ignore these flags for the purposes of comparing frame state:
7289 : //
7290 : // NS_FRAME_EXTERNAL_REFERENCE
7291 : // because this is set by the event state manager or the
7292 : // caret code when a frame is focused. Depending on whether
7293 : // or not the regression tests are run as the focused window
7294 : // will make this value vary randomly.
7295 : #define IRRELEVANT_FRAME_STATE_FLAGS NS_FRAME_EXTERNAL_REFERENCE
7296 :
7297 : #define FRAME_STATE_MASK (~(IRRELEVANT_FRAME_STATE_FLAGS))
7298 :
7299 0 : return GetStateBits() & FRAME_STATE_MASK;
7300 : }
7301 :
7302 : void
7303 0 : nsFrame::XMLQuote(nsString& aString)
7304 : {
7305 0 : int32_t i, len = aString.Length();
7306 0 : for (i = 0; i < len; i++) {
7307 0 : char16_t ch = aString.CharAt(i);
7308 0 : if (ch == '<') {
7309 0 : nsAutoString tmp(NS_LITERAL_STRING("<"));
7310 0 : aString.Cut(i, 1);
7311 0 : aString.Insert(tmp, i);
7312 0 : len += 3;
7313 0 : i += 3;
7314 : }
7315 0 : else if (ch == '>') {
7316 0 : nsAutoString tmp(NS_LITERAL_STRING(">"));
7317 0 : aString.Cut(i, 1);
7318 0 : aString.Insert(tmp, i);
7319 0 : len += 3;
7320 0 : i += 3;
7321 : }
7322 0 : else if (ch == '\"') {
7323 0 : nsAutoString tmp(NS_LITERAL_STRING("""));
7324 0 : aString.Cut(i, 1);
7325 0 : aString.Insert(tmp, i);
7326 0 : len += 5;
7327 0 : i += 5;
7328 : }
7329 : }
7330 0 : }
7331 : #endif
7332 :
7333 : bool
7334 3922 : nsIFrame::IsVisibleForPainting(nsDisplayListBuilder* aBuilder) {
7335 3922 : if (!StyleVisibility()->IsVisible())
7336 171 : return false;
7337 3751 : nsISelection* sel = aBuilder->GetBoundingSelection();
7338 3751 : return !sel || IsVisibleInSelection(sel);
7339 : }
7340 :
7341 : bool
7342 0 : nsIFrame::IsVisibleForPainting() {
7343 0 : if (!StyleVisibility()->IsVisible())
7344 0 : return false;
7345 :
7346 0 : nsPresContext* pc = PresContext();
7347 0 : if (!pc->IsRenderingOnlySelection())
7348 0 : return true;
7349 :
7350 0 : nsCOMPtr<nsISelectionController> selcon(do_QueryInterface(pc->PresShell()));
7351 0 : if (selcon) {
7352 0 : nsCOMPtr<nsISelection> sel;
7353 0 : selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
7354 0 : getter_AddRefs(sel));
7355 0 : if (sel)
7356 0 : return IsVisibleInSelection(sel);
7357 : }
7358 0 : return true;
7359 : }
7360 :
7361 : bool
7362 0 : nsIFrame::IsVisibleInSelection(nsDisplayListBuilder* aBuilder) {
7363 0 : nsISelection* sel = aBuilder->GetBoundingSelection();
7364 0 : return !sel || IsVisibleInSelection(sel);
7365 : }
7366 :
7367 : bool
7368 0 : nsIFrame::IsVisibleOrCollapsedForPainting(nsDisplayListBuilder* aBuilder) {
7369 0 : if (!StyleVisibility()->IsVisibleOrCollapsed())
7370 0 : return false;
7371 0 : nsISelection* sel = aBuilder->GetBoundingSelection();
7372 0 : return !sel || IsVisibleInSelection(sel);
7373 : }
7374 :
7375 : bool
7376 0 : nsIFrame::IsVisibleInSelection(nsISelection* aSelection)
7377 : {
7378 0 : if (!GetContent() || !GetContent()->IsSelectionDescendant()) {
7379 0 : return false;
7380 : }
7381 :
7382 0 : nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
7383 : bool vis;
7384 0 : nsresult rv = aSelection->ContainsNode(node, true, &vis);
7385 0 : return NS_FAILED(rv) || vis;
7386 : }
7387 :
7388 : /* virtual */ bool
7389 106 : nsFrame::IsEmpty()
7390 : {
7391 106 : return false;
7392 : }
7393 :
7394 : bool
7395 75 : nsIFrame::CachedIsEmpty()
7396 : {
7397 75 : NS_PRECONDITION(!(GetStateBits() & NS_FRAME_IS_DIRTY),
7398 : "Must only be called on reflowed lines");
7399 75 : return IsEmpty();
7400 : }
7401 :
7402 : /* virtual */ bool
7403 0 : nsFrame::IsSelfEmpty()
7404 : {
7405 0 : return false;
7406 : }
7407 :
7408 : nsresult
7409 1 : nsFrame::GetSelectionController(nsPresContext *aPresContext, nsISelectionController **aSelCon)
7410 : {
7411 1 : if (!aPresContext || !aSelCon)
7412 0 : return NS_ERROR_INVALID_ARG;
7413 :
7414 1 : nsIFrame *frame = this;
7415 1 : while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
7416 0 : nsITextControlFrame *tcf = do_QueryFrame(frame);
7417 0 : if (tcf) {
7418 0 : return tcf->GetOwnedSelectionController(aSelCon);
7419 : }
7420 0 : frame = frame->GetParent();
7421 : }
7422 :
7423 1 : return CallQueryInterface(aPresContext->GetPresShell(), aSelCon);
7424 : }
7425 :
7426 : already_AddRefed<nsFrameSelection>
7427 4 : nsIFrame::GetFrameSelection()
7428 : {
7429 : RefPtr<nsFrameSelection> fs =
7430 8 : const_cast<nsFrameSelection*>(GetConstFrameSelection());
7431 8 : return fs.forget();
7432 : }
7433 :
7434 : const nsFrameSelection*
7435 8 : nsIFrame::GetConstFrameSelection() const
7436 : {
7437 8 : nsIFrame* frame = const_cast<nsIFrame*>(this);
7438 20 : while (frame && (frame->GetStateBits() & NS_FRAME_INDEPENDENT_SELECTION)) {
7439 10 : nsITextControlFrame* tcf = do_QueryFrame(frame);
7440 10 : if (tcf) {
7441 4 : return tcf->GetOwnedFrameSelection();
7442 : }
7443 6 : frame = frame->GetParent();
7444 : }
7445 :
7446 4 : return PresContext()->PresShell()->ConstFrameSelection();
7447 : }
7448 :
7449 : #ifdef DEBUG
7450 : nsresult
7451 0 : nsFrame::DumpRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
7452 : {
7453 0 : IndentBy(out, aIndent);
7454 0 : fprintf(out, "<frame va=\"%p\" type=\"", (void*)this);
7455 0 : nsAutoString name;
7456 0 : GetFrameName(name);
7457 0 : XMLQuote(name);
7458 0 : fputs(NS_LossyConvertUTF16toASCII(name).get(), out);
7459 : fprintf(out, "\" state=\"%016llx\" parent=\"%p\">\n",
7460 0 : (unsigned long long)GetDebugStateBits(), (void*)GetParent());
7461 :
7462 0 : aIndent++;
7463 0 : DumpBaseRegressionData(aPresContext, out, aIndent);
7464 0 : aIndent--;
7465 :
7466 0 : IndentBy(out, aIndent);
7467 0 : fprintf(out, "</frame>\n");
7468 :
7469 0 : return NS_OK;
7470 : }
7471 :
7472 : void
7473 0 : nsFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
7474 : {
7475 0 : if (GetNextSibling()) {
7476 0 : IndentBy(out, aIndent);
7477 0 : fprintf(out, "<next-sibling va=\"%p\"/>\n", (void*)GetNextSibling());
7478 : }
7479 :
7480 0 : if (HasView()) {
7481 0 : IndentBy(out, aIndent);
7482 0 : fprintf(out, "<view va=\"%p\">\n", (void*)GetView());
7483 0 : aIndent++;
7484 : // XXX add in code to dump out view state too...
7485 0 : aIndent--;
7486 0 : IndentBy(out, aIndent);
7487 0 : fprintf(out, "</view>\n");
7488 : }
7489 :
7490 0 : IndentBy(out, aIndent);
7491 0 : fprintf(out, "<bbox x=\"%d\" y=\"%d\" w=\"%d\" h=\"%d\"/>\n",
7492 0 : mRect.x, mRect.y, mRect.width, mRect.height);
7493 :
7494 : // Now dump all of the children on all of the child lists
7495 0 : ChildListIterator lists(this);
7496 0 : for (; !lists.IsDone(); lists.Next()) {
7497 0 : IndentBy(out, aIndent);
7498 0 : if (lists.CurrentID() != kPrincipalList) {
7499 0 : fprintf(out, "<child-list name=\"%s\">\n", mozilla::layout::ChildListName(lists.CurrentID()));
7500 : }
7501 : else {
7502 0 : fprintf(out, "<child-list>\n");
7503 : }
7504 0 : aIndent++;
7505 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
7506 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
7507 0 : nsIFrame* kid = childFrames.get();
7508 0 : kid->DumpRegressionData(aPresContext, out, aIndent);
7509 : }
7510 0 : aIndent--;
7511 0 : IndentBy(out, aIndent);
7512 0 : fprintf(out, "</child-list>\n");
7513 : }
7514 0 : }
7515 : #endif
7516 :
7517 : bool
7518 0 : nsIFrame::IsFrameSelected() const
7519 : {
7520 0 : NS_ASSERTION(!GetContent() || GetContent()->IsSelectionDescendant(),
7521 : "use the public IsSelected() instead");
7522 0 : return nsRange::IsNodeSelected(GetContent(), 0,
7523 0 : GetContent()->GetChildCount());
7524 : }
7525 :
7526 : nsresult
7527 0 : nsFrame::GetPointFromOffset(int32_t inOffset, nsPoint* outPoint)
7528 : {
7529 0 : NS_PRECONDITION(outPoint != nullptr, "Null parameter");
7530 0 : nsRect contentRect = GetContentRectRelativeToSelf();
7531 0 : nsPoint pt = contentRect.TopLeft();
7532 0 : if (mContent)
7533 : {
7534 0 : nsIContent* newContent = mContent->GetParent();
7535 0 : if (newContent){
7536 0 : int32_t newOffset = newContent->IndexOf(mContent);
7537 :
7538 : // Find the direction of the frame from the EmbeddingLevelProperty,
7539 : // which is the resolved bidi level set in
7540 : // nsBidiPresUtils::ResolveParagraph (odd levels = right-to-left).
7541 : // If the embedding level isn't set, just use the CSS direction
7542 : // property.
7543 : bool hasBidiData;
7544 0 : FrameBidiData bidiData = GetProperty(BidiDataProperty(), &hasBidiData);
7545 : bool isRTL = hasBidiData
7546 0 : ? IS_LEVEL_RTL(bidiData.embeddingLevel)
7547 0 : : StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
7548 0 : if ((!isRTL && inOffset > newOffset) ||
7549 0 : (isRTL && inOffset <= newOffset)) {
7550 0 : pt = contentRect.TopRight();
7551 : }
7552 : }
7553 : }
7554 0 : *outPoint = pt;
7555 0 : return NS_OK;
7556 : }
7557 :
7558 : nsresult
7559 0 : nsFrame::GetCharacterRectsInRange(int32_t aInOffset, int32_t aLength,
7560 : nsTArray<nsRect>& aOutRect)
7561 : {
7562 : /* no text */
7563 0 : return NS_ERROR_FAILURE;
7564 : }
7565 :
7566 : nsresult
7567 4 : nsFrame::GetChildFrameContainingOffset(int32_t inContentOffset, bool inHint, int32_t* outFrameContentOffset, nsIFrame **outChildFrame)
7568 : {
7569 4 : NS_PRECONDITION(outChildFrame && outFrameContentOffset, "Null parameter");
7570 4 : *outFrameContentOffset = (int32_t)inHint;
7571 : //the best frame to reflect any given offset would be a visible frame if possible
7572 : //i.e. we are looking for a valid frame to place the blinking caret
7573 8 : nsRect rect = GetRect();
7574 4 : if (!rect.width || !rect.height)
7575 : {
7576 : //if we have a 0 width or height then lets look for another frame that possibly has
7577 : //the same content. If we have no frames in flow then just let us return 'this' frame
7578 4 : nsIFrame* nextFlow = GetNextInFlow();
7579 4 : if (nextFlow)
7580 0 : return nextFlow->GetChildFrameContainingOffset(inContentOffset, inHint, outFrameContentOffset, outChildFrame);
7581 : }
7582 4 : *outChildFrame = this;
7583 4 : return NS_OK;
7584 : }
7585 :
7586 : //
7587 : // What I've pieced together about this routine:
7588 : // Starting with a block frame (from which a line frame can be gotten)
7589 : // and a line number, drill down and get the first/last selectable
7590 : // frame on that line, depending on aPos->mDirection.
7591 : // aOutSideLimit != 0 means ignore aLineStart, instead work from
7592 : // the end (if > 0) or beginning (if < 0).
7593 : //
7594 : nsresult
7595 0 : nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext,
7596 : nsPeekOffsetStruct *aPos,
7597 : nsIFrame *aBlockFrame,
7598 : int32_t aLineStart,
7599 : int8_t aOutSideLimit
7600 : )
7601 : {
7602 : //magic numbers aLineStart will be -1 for end of block 0 will be start of block
7603 0 : if (!aBlockFrame || !aPos)
7604 0 : return NS_ERROR_NULL_POINTER;
7605 :
7606 0 : aPos->mResultFrame = nullptr;
7607 0 : aPos->mResultContent = nullptr;
7608 0 : aPos->mAttach =
7609 0 : aPos->mDirection == eDirNext ? CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
7610 :
7611 0 : nsAutoLineIterator it = aBlockFrame->GetLineIterator();
7612 0 : if (!it)
7613 0 : return NS_ERROR_FAILURE;
7614 0 : int32_t searchingLine = aLineStart;
7615 0 : int32_t countLines = it->GetNumLines();
7616 0 : if (aOutSideLimit > 0) //start at end
7617 0 : searchingLine = countLines;
7618 0 : else if (aOutSideLimit <0)//start at beginning
7619 0 : searchingLine = -1;//"next" will be 0
7620 : else
7621 0 : if ((aPos->mDirection == eDirPrevious && searchingLine == 0) ||
7622 0 : (aPos->mDirection == eDirNext && searchingLine >= (countLines -1) )){
7623 : //we need to jump to new block frame.
7624 0 : return NS_ERROR_FAILURE;
7625 : }
7626 : int32_t lineFrameCount;
7627 0 : nsIFrame *resultFrame = nullptr;
7628 0 : nsIFrame *farStoppingFrame = nullptr; //we keep searching until we find a "this" frame then we go to next line
7629 0 : nsIFrame *nearStoppingFrame = nullptr; //if we are backing up from edge, stop here
7630 : nsIFrame *firstFrame;
7631 : nsIFrame *lastFrame;
7632 0 : nsRect rect;
7633 : bool isBeforeFirstFrame, isAfterLastFrame;
7634 0 : bool found = false;
7635 :
7636 0 : nsresult result = NS_OK;
7637 0 : while (!found)
7638 : {
7639 0 : if (aPos->mDirection == eDirPrevious)
7640 0 : searchingLine --;
7641 : else
7642 0 : searchingLine ++;
7643 0 : if ((aPos->mDirection == eDirPrevious && searchingLine < 0) ||
7644 0 : (aPos->mDirection == eDirNext && searchingLine >= countLines ))
7645 : {
7646 : //we need to jump to new block frame.
7647 0 : return NS_ERROR_FAILURE;
7648 : }
7649 0 : result = it->GetLine(searchingLine, &firstFrame, &lineFrameCount,
7650 0 : rect);
7651 0 : if (!lineFrameCount)
7652 0 : continue;
7653 0 : if (NS_SUCCEEDED(result)){
7654 0 : lastFrame = firstFrame;
7655 0 : for (;lineFrameCount > 1;lineFrameCount --){
7656 : //result = lastFrame->GetNextSibling(&lastFrame, searchingLine);
7657 0 : result = it->GetNextSiblingOnLine(lastFrame, searchingLine);
7658 0 : if (NS_FAILED(result) || !lastFrame){
7659 0 : NS_ERROR("GetLine promised more frames than could be found");
7660 0 : return NS_ERROR_FAILURE;
7661 : }
7662 : }
7663 0 : GetLastLeaf(aPresContext, &lastFrame);
7664 :
7665 0 : if (aPos->mDirection == eDirNext){
7666 0 : nearStoppingFrame = firstFrame;
7667 0 : farStoppingFrame = lastFrame;
7668 : }
7669 : else{
7670 0 : nearStoppingFrame = lastFrame;
7671 0 : farStoppingFrame = firstFrame;
7672 : }
7673 0 : nsPoint offset;
7674 : nsView * view; //used for call of get offset from view
7675 0 : aBlockFrame->GetOffsetFromView(offset,&view);
7676 : nsPoint newDesiredPos =
7677 0 : aPos->mDesiredPos - offset; //get desired position into blockframe coords
7678 0 : result = it->FindFrameAt(searchingLine, newDesiredPos, &resultFrame,
7679 0 : &isBeforeFirstFrame, &isAfterLastFrame);
7680 0 : if(NS_FAILED(result))
7681 0 : continue;
7682 : }
7683 :
7684 0 : if (NS_SUCCEEDED(result) && resultFrame)
7685 : {
7686 : //check to see if this is ANOTHER blockframe inside the other one if so then call into its lines
7687 0 : nsAutoLineIterator newIt = resultFrame->GetLineIterator();
7688 0 : if (newIt)
7689 : {
7690 0 : aPos->mResultFrame = resultFrame;
7691 0 : return NS_OK;
7692 : }
7693 : //resultFrame is not a block frame
7694 0 : result = NS_ERROR_FAILURE;
7695 :
7696 0 : nsCOMPtr<nsIFrameEnumerator> frameTraversal;
7697 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
7698 : aPresContext, resultFrame,
7699 : ePostOrder,
7700 : false, // aVisual
7701 0 : aPos->mScrollViewStop,
7702 : false, // aFollowOOFs
7703 : false // aSkipPopupChecks
7704 0 : );
7705 0 : if (NS_FAILED(result))
7706 0 : return result;
7707 :
7708 0 : nsIFrame *storeOldResultFrame = resultFrame;
7709 0 : while ( !found ){
7710 0 : nsPoint point;
7711 0 : nsRect tempRect = resultFrame->GetRect();
7712 0 : nsPoint offset;
7713 : nsView * view; //used for call of get offset from view
7714 0 : resultFrame->GetOffsetFromView(offset, &view);
7715 0 : if (!view) {
7716 0 : return NS_ERROR_FAILURE;
7717 : }
7718 0 : if (resultFrame->GetWritingMode().IsVertical()) {
7719 0 : point.y = aPos->mDesiredPos.y;
7720 0 : point.x = tempRect.width + offset.x;
7721 : } else {
7722 0 : point.y = tempRect.height + offset.y;
7723 0 : point.x = aPos->mDesiredPos.x;
7724 : }
7725 :
7726 : //special check. if we allow non-text selection then we can allow a hit location to fall before a table.
7727 : //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself)
7728 0 : nsIPresShell *shell = aPresContext->GetPresShell();
7729 0 : if (!shell)
7730 0 : return NS_ERROR_FAILURE;
7731 0 : int16_t isEditor = shell->GetSelectionFlags();
7732 0 : isEditor = isEditor == nsISelectionDisplay::DISPLAY_ALL;
7733 0 : if ( isEditor )
7734 : {
7735 0 : if (resultFrame->IsTableWrapperFrame()) {
7736 0 : if (((point.x - offset.x + tempRect.x)<0) || ((point.x - offset.x+ tempRect.x)>tempRect.width))//off left/right side
7737 : {
7738 0 : nsIContent* content = resultFrame->GetContent();
7739 0 : if (content)
7740 : {
7741 0 : nsIContent* parent = content->GetParent();
7742 0 : if (parent)
7743 : {
7744 0 : aPos->mResultContent = parent;
7745 0 : aPos->mContentOffset = parent->IndexOf(content);
7746 0 : aPos->mAttach = CARET_ASSOCIATE_BEFORE;
7747 0 : if ((point.x - offset.x+ tempRect.x)>tempRect.width)
7748 : {
7749 0 : aPos->mContentOffset++;//go to end of this frame
7750 0 : aPos->mAttach = CARET_ASSOCIATE_AFTER;
7751 : }
7752 : //result frame is the result frames parent.
7753 0 : aPos->mResultFrame = resultFrame->GetParent();
7754 0 : return NS_POSITION_BEFORE_TABLE;
7755 : }
7756 : }
7757 : }
7758 : }
7759 : }
7760 :
7761 0 : if (!resultFrame->HasView())
7762 : {
7763 : nsView* view;
7764 0 : nsPoint offset;
7765 0 : resultFrame->GetOffsetFromView(offset, &view);
7766 : ContentOffsets offsets =
7767 0 : resultFrame->GetContentOffsetsFromPoint(point - offset);
7768 0 : aPos->mResultContent = offsets.content;
7769 0 : aPos->mContentOffset = offsets.offset;
7770 0 : aPos->mAttach = offsets.associate;
7771 0 : if (offsets.content)
7772 : {
7773 0 : if (resultFrame->IsSelectable(nullptr)) {
7774 0 : found = true;
7775 0 : break;
7776 : }
7777 : }
7778 : }
7779 :
7780 0 : if (aPos->mDirection == eDirPrevious && (resultFrame == farStoppingFrame))
7781 0 : break;
7782 0 : if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame))
7783 0 : break;
7784 : //always try previous on THAT line if that fails go the other way
7785 0 : frameTraversal->Prev();
7786 0 : resultFrame = frameTraversal->CurrentItem();
7787 0 : if (!resultFrame)
7788 0 : return NS_ERROR_FAILURE;
7789 : }
7790 :
7791 0 : if (!found){
7792 0 : resultFrame = storeOldResultFrame;
7793 :
7794 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
7795 : aPresContext, resultFrame,
7796 : eLeaf,
7797 : false, // aVisual
7798 0 : aPos->mScrollViewStop,
7799 : false, // aFollowOOFs
7800 : false // aSkipPopupChecks
7801 0 : );
7802 : }
7803 0 : while ( !found ){
7804 0 : nsPoint point = aPos->mDesiredPos;
7805 : nsView* view;
7806 0 : nsPoint offset;
7807 0 : resultFrame->GetOffsetFromView(offset, &view);
7808 : ContentOffsets offsets =
7809 0 : resultFrame->GetContentOffsetsFromPoint(point - offset);
7810 0 : aPos->mResultContent = offsets.content;
7811 0 : aPos->mContentOffset = offsets.offset;
7812 0 : aPos->mAttach = offsets.associate;
7813 0 : if (offsets.content)
7814 : {
7815 0 : if (resultFrame->IsSelectable(nullptr)) {
7816 0 : found = true;
7817 0 : if (resultFrame == farStoppingFrame)
7818 0 : aPos->mAttach = CARET_ASSOCIATE_BEFORE;
7819 : else
7820 0 : aPos->mAttach = CARET_ASSOCIATE_AFTER;
7821 0 : break;
7822 : }
7823 : }
7824 0 : if (aPos->mDirection == eDirPrevious && (resultFrame == nearStoppingFrame))
7825 0 : break;
7826 0 : if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame))
7827 0 : break;
7828 : //previous didnt work now we try "next"
7829 0 : frameTraversal->Next();
7830 0 : nsIFrame *tempFrame = frameTraversal->CurrentItem();
7831 0 : if (!tempFrame)
7832 0 : break;
7833 0 : resultFrame = tempFrame;
7834 : }
7835 0 : aPos->mResultFrame = resultFrame;
7836 : }
7837 : else {
7838 : //we need to jump to new block frame.
7839 0 : aPos->mAmount = eSelectLine;
7840 0 : aPos->mStartOffset = 0;
7841 0 : aPos->mAttach = aPos->mDirection == eDirNext ?
7842 : CARET_ASSOCIATE_BEFORE : CARET_ASSOCIATE_AFTER;
7843 0 : if (aPos->mDirection == eDirPrevious)
7844 0 : aPos->mStartOffset = -1;//start from end
7845 0 : return aBlockFrame->PeekOffset(aPos);
7846 : }
7847 : }
7848 0 : return NS_OK;
7849 : }
7850 :
7851 : nsIFrame::CaretPosition
7852 0 : nsIFrame::GetExtremeCaretPosition(bool aStart)
7853 : {
7854 0 : CaretPosition result;
7855 :
7856 0 : FrameTarget targetFrame = DrillDownToSelectionFrame(this, !aStart, 0);
7857 0 : FrameContentRange range = GetRangeForFrame(targetFrame.frame);
7858 0 : result.mResultContent = range.content;
7859 0 : result.mContentOffset = aStart ? range.start : range.end;
7860 0 : return result;
7861 : }
7862 :
7863 : // Find the first (or last) descendant of the given frame
7864 : // which is either a block frame or a BRFrame.
7865 : static nsContentAndOffset
7866 0 : FindBlockFrameOrBR(nsIFrame* aFrame, nsDirection aDirection)
7867 : {
7868 : nsContentAndOffset result;
7869 0 : result.mContent = nullptr;
7870 0 : result.mOffset = 0;
7871 :
7872 0 : if (aFrame->IsGeneratedContentFrame())
7873 0 : return result;
7874 :
7875 : // Treat form controls as inline leaves
7876 : // XXX we really need a way to determine whether a frame is inline-level
7877 0 : nsIFormControlFrame* fcf = do_QueryFrame(aFrame);
7878 0 : if (fcf)
7879 0 : return result;
7880 :
7881 : // Check the frame itself
7882 : // Fall through block-in-inline split frames because their mContent is
7883 : // the content of the inline frames they were created from. The
7884 : // first/last child of such frames is the real block frame we're
7885 : // looking for.
7886 0 : if ((nsLayoutUtils::GetAsBlock(aFrame) &&
7887 0 : !(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) ||
7888 0 : aFrame->IsBrFrame()) {
7889 0 : nsIContent* content = aFrame->GetContent();
7890 0 : result.mContent = content->GetParent();
7891 : // In some cases (bug 310589, bug 370174) we end up here with a null content.
7892 : // This probably shouldn't ever happen, but since it sometimes does, we want
7893 : // to avoid crashing here.
7894 0 : NS_ASSERTION(result.mContent, "Unexpected orphan content");
7895 0 : if (result.mContent)
7896 0 : result.mOffset = result.mContent->IndexOf(content) +
7897 0 : (aDirection == eDirPrevious ? 1 : 0);
7898 0 : return result;
7899 : }
7900 :
7901 : // If this is a preformatted text frame, see if it ends with a newline
7902 0 : if (aFrame->HasSignificantTerminalNewline()) {
7903 : int32_t startOffset, endOffset;
7904 0 : aFrame->GetOffsets(startOffset, endOffset);
7905 0 : result.mContent = aFrame->GetContent();
7906 0 : result.mOffset = endOffset - (aDirection == eDirPrevious ? 0 : 1);
7907 0 : return result;
7908 : }
7909 :
7910 : // Iterate over children and call ourselves recursively
7911 0 : if (aDirection == eDirPrevious) {
7912 0 : nsIFrame* child = aFrame->GetChildList(nsIFrame::kPrincipalList).LastChild();
7913 0 : while(child && !result.mContent) {
7914 0 : result = FindBlockFrameOrBR(child, aDirection);
7915 0 : child = child->GetPrevSibling();
7916 : }
7917 : } else { // eDirNext
7918 0 : nsIFrame* child = aFrame->PrincipalChildList().FirstChild();
7919 0 : while(child && !result.mContent) {
7920 0 : result = FindBlockFrameOrBR(child, aDirection);
7921 0 : child = child->GetNextSibling();
7922 : }
7923 : }
7924 0 : return result;
7925 : }
7926 :
7927 : nsresult
7928 0 : nsIFrame::PeekOffsetParagraph(nsPeekOffsetStruct *aPos)
7929 : {
7930 0 : nsIFrame* frame = this;
7931 : nsContentAndOffset blockFrameOrBR;
7932 0 : blockFrameOrBR.mContent = nullptr;
7933 0 : bool reachedBlockAncestor = false;
7934 :
7935 : // Go through containing frames until reaching a block frame.
7936 : // In each step, search the previous (or next) siblings for the closest
7937 : // "stop frame" (a block frame or a BRFrame).
7938 : // If found, set it to be the selection boundray and abort.
7939 :
7940 0 : if (aPos->mDirection == eDirPrevious) {
7941 0 : while (!reachedBlockAncestor) {
7942 0 : nsIFrame* parent = frame->GetParent();
7943 : // Treat a frame associated with the root content as if it were a block frame.
7944 0 : if (!frame->mContent || !frame->mContent->GetParent()) {
7945 0 : reachedBlockAncestor = true;
7946 0 : break;
7947 : }
7948 0 : nsIFrame* sibling = frame->GetPrevSibling();
7949 0 : while (sibling && !blockFrameOrBR.mContent) {
7950 0 : blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirPrevious);
7951 0 : sibling = sibling->GetPrevSibling();
7952 : }
7953 0 : if (blockFrameOrBR.mContent) {
7954 0 : aPos->mResultContent = blockFrameOrBR.mContent;
7955 0 : aPos->mContentOffset = blockFrameOrBR.mOffset;
7956 0 : break;
7957 : }
7958 0 : frame = parent;
7959 0 : reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr);
7960 : }
7961 0 : if (reachedBlockAncestor) { // no "stop frame" found
7962 0 : aPos->mResultContent = frame->GetContent();
7963 0 : aPos->mContentOffset = 0;
7964 : }
7965 : } else { // eDirNext
7966 0 : while (!reachedBlockAncestor) {
7967 0 : nsIFrame* parent = frame->GetParent();
7968 : // Treat a frame associated with the root content as if it were a block frame.
7969 0 : if (!frame->mContent || !frame->mContent->GetParent()) {
7970 0 : reachedBlockAncestor = true;
7971 0 : break;
7972 : }
7973 0 : nsIFrame* sibling = frame;
7974 0 : while (sibling && !blockFrameOrBR.mContent) {
7975 0 : blockFrameOrBR = FindBlockFrameOrBR(sibling, eDirNext);
7976 0 : sibling = sibling->GetNextSibling();
7977 : }
7978 0 : if (blockFrameOrBR.mContent) {
7979 0 : aPos->mResultContent = blockFrameOrBR.mContent;
7980 0 : aPos->mContentOffset = blockFrameOrBR.mOffset;
7981 0 : break;
7982 : }
7983 0 : frame = parent;
7984 0 : reachedBlockAncestor = (nsLayoutUtils::GetAsBlock(frame) != nullptr);
7985 : }
7986 0 : if (reachedBlockAncestor) { // no "stop frame" found
7987 0 : aPos->mResultContent = frame->GetContent();
7988 0 : if (aPos->mResultContent)
7989 0 : aPos->mContentOffset = aPos->mResultContent->GetChildCount();
7990 : }
7991 : }
7992 0 : return NS_OK;
7993 : }
7994 :
7995 : // Determine movement direction relative to frame
7996 0 : static bool IsMovingInFrameDirection(nsIFrame* frame, nsDirection aDirection, bool aVisual)
7997 : {
7998 0 : bool isReverseDirection = aVisual && IsReversedDirectionFrame(frame);
7999 0 : return aDirection == (isReverseDirection ? eDirPrevious : eDirNext);
8000 : }
8001 :
8002 : nsresult
8003 0 : nsIFrame::PeekOffset(nsPeekOffsetStruct* aPos)
8004 : {
8005 0 : if (!aPos)
8006 0 : return NS_ERROR_NULL_POINTER;
8007 0 : nsresult result = NS_ERROR_FAILURE;
8008 :
8009 0 : if (mState & NS_FRAME_IS_DIRTY)
8010 0 : return NS_ERROR_UNEXPECTED;
8011 :
8012 : // Translate content offset to be relative to frame
8013 0 : FrameContentRange range = GetRangeForFrame(this);
8014 0 : int32_t offset = aPos->mStartOffset - range.start;
8015 0 : nsIFrame* current = this;
8016 :
8017 0 : switch (aPos->mAmount) {
8018 : case eSelectCharacter:
8019 : case eSelectCluster:
8020 : {
8021 0 : bool eatingNonRenderableWS = false;
8022 0 : nsIFrame::FrameSearchResult peekSearchState = CONTINUE;
8023 0 : bool jumpedLine = false;
8024 0 : bool movedOverNonSelectableText = false;
8025 :
8026 0 : while (peekSearchState != FOUND) {
8027 : bool movingInFrameDirection =
8028 0 : IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
8029 :
8030 0 : if (eatingNonRenderableWS) {
8031 0 : peekSearchState = current->PeekOffsetNoAmount(movingInFrameDirection, &offset);
8032 : } else {
8033 0 : PeekOffsetCharacterOptions options;
8034 0 : options.mRespectClusters = aPos->mAmount == eSelectCluster;
8035 0 : peekSearchState = current->PeekOffsetCharacter(movingInFrameDirection,
8036 0 : &offset, options);
8037 : }
8038 :
8039 0 : movedOverNonSelectableText |= (peekSearchState == CONTINUE_UNSELECTABLE);
8040 :
8041 0 : if (peekSearchState != FOUND) {
8042 0 : bool movedOverNonSelectable = false;
8043 : result =
8044 0 : current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
8045 0 : aPos->mJumpLines, aPos->mScrollViewStop,
8046 : ¤t, &offset, &jumpedLine,
8047 0 : &movedOverNonSelectable);
8048 0 : if (NS_FAILED(result))
8049 0 : return result;
8050 :
8051 : // If we jumped lines, it's as if we found a character, but we still need
8052 : // to eat non-renderable content on the new line.
8053 0 : if (jumpedLine)
8054 0 : eatingNonRenderableWS = true;
8055 :
8056 : // Remember if we moved over non-selectable text when finding another frame.
8057 0 : if (movedOverNonSelectable) {
8058 0 : movedOverNonSelectableText = true;
8059 : }
8060 : }
8061 :
8062 : // Found frame, but because we moved over non selectable text we want the offset
8063 : // to be at the frame edge. Note that if we are extending the selection, this
8064 : // doesn't matter.
8065 0 : if (peekSearchState == FOUND && movedOverNonSelectableText &&
8066 0 : !aPos->mExtend)
8067 : {
8068 : int32_t start, end;
8069 0 : current->GetOffsets(start, end);
8070 0 : offset = aPos->mDirection == eDirNext ? 0 : end - start;
8071 : }
8072 : }
8073 :
8074 : // Set outputs
8075 0 : range = GetRangeForFrame(current);
8076 0 : aPos->mResultFrame = current;
8077 0 : aPos->mResultContent = range.content;
8078 : // Output offset is relative to content, not frame
8079 0 : aPos->mContentOffset = offset < 0 ? range.end : range.start + offset;
8080 : // If we're dealing with a text frame and moving backward positions us at
8081 : // the end of that line, decrease the offset by one to make sure that
8082 : // we're placed before the linefeed character on the previous line.
8083 0 : if (offset < 0 && jumpedLine &&
8084 0 : aPos->mDirection == eDirPrevious &&
8085 0 : current->HasSignificantTerminalNewline()) {
8086 0 : --aPos->mContentOffset;
8087 : }
8088 :
8089 0 : break;
8090 : }
8091 : case eSelectWordNoSpace:
8092 : // eSelectWordNoSpace means that we should not be eating any whitespace when
8093 : // moving to the adjacent word. This means that we should set aPos->
8094 : // mWordMovementType to eEndWord if we're moving forwards, and to eStartWord
8095 : // if we're moving backwards.
8096 0 : if (aPos->mDirection == eDirPrevious) {
8097 0 : aPos->mWordMovementType = eStartWord;
8098 : } else {
8099 0 : aPos->mWordMovementType = eEndWord;
8100 : }
8101 : // Intentionally fall through the eSelectWord case.
8102 : MOZ_FALLTHROUGH;
8103 : case eSelectWord:
8104 : {
8105 : // wordSelectEatSpace means "are we looking for a boundary between whitespace
8106 : // and non-whitespace (in the direction we're moving in)".
8107 : // It is true when moving forward and looking for a beginning of a word, or
8108 : // when moving backwards and looking for an end of a word.
8109 : bool wordSelectEatSpace;
8110 0 : if (aPos->mWordMovementType != eDefaultBehavior) {
8111 : // aPos->mWordMovementType possible values:
8112 : // eEndWord: eat the space if we're moving backwards
8113 : // eStartWord: eat the space if we're moving forwards
8114 0 : wordSelectEatSpace = ((aPos->mWordMovementType == eEndWord) == (aPos->mDirection == eDirPrevious));
8115 : }
8116 : else {
8117 : // Use the hidden preference which is based on operating system behavior.
8118 : // This pref only affects whether moving forward by word should go to the end of this word or start of the next word.
8119 : // When going backwards, the start of the word is always used, on every operating system.
8120 0 : wordSelectEatSpace = aPos->mDirection == eDirNext &&
8121 0 : Preferences::GetBool("layout.word_select.eat_space_to_next_word");
8122 : }
8123 :
8124 : // mSawBeforeType means "we already saw characters of the type
8125 : // before the boundary we're looking for". Examples:
8126 : // 1. If we're moving forward, looking for a word beginning (i.e. a boundary
8127 : // between whitespace and non-whitespace), then eatingWS==true means
8128 : // "we already saw some whitespace".
8129 : // 2. If we're moving backward, looking for a word beginning (i.e. a boundary
8130 : // between non-whitespace and whitespace), then eatingWS==true means
8131 : // "we already saw some non-whitespace".
8132 0 : PeekWordState state;
8133 0 : int32_t offsetAdjustment = 0;
8134 0 : bool done = false;
8135 0 : while (!done) {
8136 : bool movingInFrameDirection =
8137 0 : IsMovingInFrameDirection(current, aPos->mDirection, aPos->mVisual);
8138 :
8139 0 : done = current->PeekOffsetWord(movingInFrameDirection, wordSelectEatSpace,
8140 0 : aPos->mIsKeyboardSelect, &offset, &state) == FOUND;
8141 :
8142 0 : if (!done) {
8143 : nsIFrame* nextFrame;
8144 : int32_t nextFrameOffset;
8145 : bool jumpedLine, movedOverNonSelectableText;
8146 : result =
8147 0 : current->GetFrameFromDirection(aPos->mDirection, aPos->mVisual,
8148 0 : aPos->mJumpLines, aPos->mScrollViewStop,
8149 : &nextFrame, &nextFrameOffset, &jumpedLine,
8150 0 : &movedOverNonSelectableText);
8151 : // We can't jump lines if we're looking for whitespace following
8152 : // non-whitespace, and we already encountered non-whitespace.
8153 0 : if (NS_FAILED(result) ||
8154 0 : (jumpedLine && !wordSelectEatSpace && state.mSawBeforeType)) {
8155 0 : done = true;
8156 : // If we've crossed the line boundary, check to make sure that we
8157 : // have not consumed a trailing newline as whitesapce if it's significant.
8158 0 : if (jumpedLine && wordSelectEatSpace &&
8159 0 : current->HasSignificantTerminalNewline()) {
8160 0 : offsetAdjustment = -1;
8161 : }
8162 : } else {
8163 0 : if (jumpedLine) {
8164 0 : state.mContext.Truncate();
8165 : }
8166 0 : current = nextFrame;
8167 0 : offset = nextFrameOffset;
8168 : // Jumping a line is equivalent to encountering whitespace
8169 0 : if (wordSelectEatSpace && jumpedLine)
8170 0 : state.SetSawBeforeType();
8171 : }
8172 : }
8173 : }
8174 :
8175 : // Set outputs
8176 0 : range = GetRangeForFrame(current);
8177 0 : aPos->mResultFrame = current;
8178 0 : aPos->mResultContent = range.content;
8179 : // Output offset is relative to content, not frame
8180 0 : aPos->mContentOffset = (offset < 0 ? range.end : range.start + offset) + offsetAdjustment;
8181 0 : break;
8182 : }
8183 : case eSelectLine :
8184 : {
8185 0 : nsAutoLineIterator iter;
8186 0 : nsIFrame *blockFrame = this;
8187 :
8188 0 : while (NS_FAILED(result)){
8189 0 : int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
8190 0 : if (thisLine < 0)
8191 0 : return NS_ERROR_FAILURE;
8192 0 : iter = blockFrame->GetLineIterator();
8193 0 : NS_ASSERTION(iter, "GetLineNumber() succeeded but no block frame?");
8194 0 : result = NS_OK;
8195 :
8196 0 : int edgeCase = 0; // no edge case. this should look at thisLine
8197 :
8198 0 : bool doneLooping = false; // tells us when no more block frames hit.
8199 : // this part will find a frame or a block frame. if it's a block frame
8200 : // it will "drill down" to find a viable frame or it will return an error.
8201 0 : nsIFrame *lastFrame = this;
8202 0 : do {
8203 0 : result = nsFrame::GetNextPrevLineFromeBlockFrame(PresContext(),
8204 : aPos,
8205 : blockFrame,
8206 : thisLine,
8207 0 : edgeCase); // start from thisLine
8208 :
8209 : // we came back to same spot! keep going
8210 0 : if (NS_SUCCEEDED(result) &&
8211 0 : (!aPos->mResultFrame || aPos->mResultFrame == lastFrame)) {
8212 0 : aPos->mResultFrame = nullptr;
8213 0 : if (aPos->mDirection == eDirPrevious)
8214 0 : thisLine--;
8215 : else
8216 0 : thisLine++;
8217 : } else // if failure or success with different frame.
8218 0 : doneLooping = true; // do not continue with while loop
8219 :
8220 0 : lastFrame = aPos->mResultFrame; // set last frame
8221 :
8222 : // make sure block element is not the same as the one we had before
8223 0 : if (NS_SUCCEEDED(result) &&
8224 0 : aPos->mResultFrame &&
8225 0 : blockFrame != aPos->mResultFrame) {
8226 : /* SPECIAL CHECK FOR TABLE NAVIGATION
8227 : tables need to navigate also and the frame that supports it is
8228 : nsTableRowGroupFrame which is INSIDE nsTableWrapperFrame.
8229 : If we have stumbled onto an nsTableWrapperFrame we need to drill
8230 : into nsTableRowGroup if we hit a header or footer that's ok just
8231 : go into them.
8232 : */
8233 0 : bool searchTableBool = false;
8234 0 : if (aPos->mResultFrame->IsTableWrapperFrame() ||
8235 0 : aPos->mResultFrame->IsTableCellFrame()) {
8236 0 : nsIFrame* frame = aPos->mResultFrame->PrincipalChildList().FirstChild();
8237 : // got the table frame now
8238 : // ok time to drill down to find iterator
8239 0 : while (frame) {
8240 0 : iter = frame->GetLineIterator();
8241 0 : if (iter) {
8242 0 : aPos->mResultFrame = frame;
8243 0 : searchTableBool = true;
8244 0 : result = NS_OK;
8245 0 : break; // while(frame)
8246 : }
8247 0 : result = NS_ERROR_FAILURE;
8248 0 : frame = frame->PrincipalChildList().FirstChild();
8249 : }
8250 : }
8251 :
8252 0 : if (!searchTableBool) {
8253 0 : iter = aPos->mResultFrame->GetLineIterator();
8254 0 : result = iter ? NS_OK : NS_ERROR_FAILURE;
8255 : }
8256 :
8257 : // we've struck another block element!
8258 0 : if (NS_SUCCEEDED(result) && iter) {
8259 0 : doneLooping = false;
8260 0 : if (aPos->mDirection == eDirPrevious)
8261 0 : edgeCase = 1; // far edge, search from end backwards
8262 : else
8263 0 : edgeCase = -1; // near edge search from beginning onwards
8264 0 : thisLine = 0; // this line means nothing now.
8265 : // everything else means something so keep looking "inside" the block
8266 0 : blockFrame = aPos->mResultFrame;
8267 : } else {
8268 : // THIS is to mean that everything is ok to the containing while loop
8269 0 : result = NS_OK;
8270 0 : break;
8271 : }
8272 : }
8273 0 : } while (!doneLooping);
8274 : }
8275 0 : return result;
8276 : }
8277 :
8278 : case eSelectParagraph:
8279 0 : return PeekOffsetParagraph(aPos);
8280 :
8281 : case eSelectBeginLine:
8282 : case eSelectEndLine:
8283 : {
8284 : // Adjusted so that the caret can't get confused when content changes
8285 0 : nsIFrame* blockFrame = AdjustFrameForSelectionStyles(this);
8286 0 : int32_t thisLine = nsFrame::GetLineNumber(blockFrame, aPos->mScrollViewStop, &blockFrame);
8287 0 : if (thisLine < 0)
8288 0 : return NS_ERROR_FAILURE;
8289 0 : nsAutoLineIterator it = blockFrame->GetLineIterator();
8290 0 : NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
8291 :
8292 : int32_t lineFrameCount;
8293 : nsIFrame *firstFrame;
8294 0 : nsRect usedRect;
8295 0 : nsIFrame* baseFrame = nullptr;
8296 0 : bool endOfLine = (eSelectEndLine == aPos->mAmount);
8297 :
8298 0 : if (aPos->mVisual && PresContext()->BidiEnabled()) {
8299 0 : bool lineIsRTL = it->GetDirection();
8300 : bool isReordered;
8301 : nsIFrame *lastFrame;
8302 0 : result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
8303 0 : baseFrame = endOfLine ? lastFrame : firstFrame;
8304 0 : if (baseFrame) {
8305 : bool frameIsRTL =
8306 0 : (nsBidiPresUtils::FrameDirection(baseFrame) == NSBIDI_RTL);
8307 : // If the direction of the frame on the edge is opposite to
8308 : // that of the line, we'll need to drill down to its opposite
8309 : // end, so reverse endOfLine.
8310 0 : if (frameIsRTL != lineIsRTL) {
8311 0 : endOfLine = !endOfLine;
8312 : }
8313 : }
8314 : } else {
8315 0 : it->GetLine(thisLine, &firstFrame, &lineFrameCount, usedRect);
8316 :
8317 0 : nsIFrame* frame = firstFrame;
8318 0 : for (int32_t count = lineFrameCount; count;
8319 : --count, frame = frame->GetNextSibling()) {
8320 0 : if (!frame->IsGeneratedContentFrame()) {
8321 : // When jumping to the end of the line with the "end" key,
8322 : // skip over brFrames
8323 0 : if (endOfLine && lineFrameCount > 1 && frame->IsBrFrame()) {
8324 0 : continue;
8325 : }
8326 0 : baseFrame = frame;
8327 0 : if (!endOfLine)
8328 0 : break;
8329 : }
8330 : }
8331 : }
8332 0 : if (!baseFrame)
8333 0 : return NS_ERROR_FAILURE;
8334 : FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame,
8335 0 : endOfLine, 0);
8336 0 : FrameContentRange range = GetRangeForFrame(targetFrame.frame);
8337 0 : aPos->mResultContent = range.content;
8338 0 : aPos->mContentOffset = endOfLine ? range.end : range.start;
8339 0 : if (endOfLine && targetFrame.frame->HasSignificantTerminalNewline()) {
8340 : // Do not position the caret after the terminating newline if we're
8341 : // trying to move to the end of line (see bug 596506)
8342 0 : --aPos->mContentOffset;
8343 : }
8344 0 : aPos->mResultFrame = targetFrame.frame;
8345 0 : aPos->mAttach = aPos->mContentOffset == range.start ?
8346 : CARET_ASSOCIATE_AFTER : CARET_ASSOCIATE_BEFORE;
8347 0 : if (!range.content)
8348 0 : return NS_ERROR_FAILURE;
8349 0 : return NS_OK;
8350 : }
8351 :
8352 : default:
8353 : {
8354 0 : NS_ASSERTION(false, "Invalid amount");
8355 0 : return NS_ERROR_FAILURE;
8356 : }
8357 : }
8358 0 : return NS_OK;
8359 : }
8360 :
8361 : nsIFrame::FrameSearchResult
8362 0 : nsFrame::PeekOffsetNoAmount(bool aForward, int32_t* aOffset)
8363 : {
8364 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
8365 : // Sure, we can stop right here.
8366 0 : return FOUND;
8367 : }
8368 :
8369 : nsIFrame::FrameSearchResult
8370 0 : nsFrame::PeekOffsetCharacter(bool aForward, int32_t* aOffset,
8371 : PeekOffsetCharacterOptions aOptions)
8372 : {
8373 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
8374 0 : int32_t startOffset = *aOffset;
8375 : // A negative offset means "end of frame", which in our case means offset 1.
8376 0 : if (startOffset < 0)
8377 0 : startOffset = 1;
8378 0 : if (aForward == (startOffset == 0)) {
8379 : // We're before the frame and moving forward, or after it and moving backwards:
8380 : // skip to the other side and we're done.
8381 0 : *aOffset = 1 - startOffset;
8382 0 : return FOUND;
8383 : }
8384 0 : return CONTINUE;
8385 : }
8386 :
8387 : nsIFrame::FrameSearchResult
8388 0 : nsFrame::PeekOffsetWord(bool aForward,
8389 : bool aWordSelectEatSpace,
8390 : bool aIsKeyboardSelect,
8391 : int32_t* aOffset,
8392 : PeekWordState* aState)
8393 : {
8394 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
8395 0 : int32_t startOffset = *aOffset;
8396 : // This isn't text, so truncate the context
8397 0 : aState->mContext.Truncate();
8398 0 : if (startOffset < 0)
8399 0 : startOffset = 1;
8400 0 : if (aForward == (startOffset == 0)) {
8401 : // We're before the frame and moving forward, or after it and moving backwards.
8402 : // If we're looking for non-whitespace, we found it (without skipping this frame).
8403 0 : if (!aState->mAtStart) {
8404 0 : if (aState->mLastCharWasPunctuation) {
8405 : // We're not punctuation, so this is a punctuation boundary.
8406 0 : if (BreakWordBetweenPunctuation(aState, aForward, false, false, aIsKeyboardSelect))
8407 0 : return FOUND;
8408 : } else {
8409 : // This is not a punctuation boundary.
8410 0 : if (aWordSelectEatSpace && aState->mSawBeforeType)
8411 0 : return FOUND;
8412 : }
8413 : }
8414 : // Otherwise skip to the other side and note that we encountered non-whitespace.
8415 0 : *aOffset = 1 - startOffset;
8416 : aState->Update(false, // not punctuation
8417 : false // not whitespace
8418 0 : );
8419 0 : if (!aWordSelectEatSpace)
8420 0 : aState->SetSawBeforeType();
8421 : }
8422 0 : return CONTINUE;
8423 : }
8424 :
8425 : bool
8426 0 : nsFrame::BreakWordBetweenPunctuation(const PeekWordState* aState,
8427 : bool aForward,
8428 : bool aPunctAfter, bool aWhitespaceAfter,
8429 : bool aIsKeyboardSelect)
8430 : {
8431 0 : NS_ASSERTION(aPunctAfter != aState->mLastCharWasPunctuation,
8432 : "Call this only at punctuation boundaries");
8433 0 : if (aState->mLastCharWasWhitespace) {
8434 : // We always stop between whitespace and punctuation
8435 0 : return true;
8436 : }
8437 0 : if (!Preferences::GetBool("layout.word_select.stop_at_punctuation")) {
8438 : // When this pref is false, we never stop at a punctuation boundary unless
8439 : // it's followed by whitespace (in the relevant direction).
8440 0 : return aWhitespaceAfter;
8441 : }
8442 0 : if (!aIsKeyboardSelect) {
8443 : // mouse caret movement (e.g. word selection) always stops at every punctuation boundary
8444 0 : return true;
8445 : }
8446 0 : bool afterPunct = aForward ? aState->mLastCharWasPunctuation : aPunctAfter;
8447 0 : if (!afterPunct) {
8448 : // keyboard caret movement only stops after punctuation (in content order)
8449 0 : return false;
8450 : }
8451 : // Stop only if we've seen some non-punctuation since the last whitespace;
8452 : // don't stop after punctuation that follows whitespace.
8453 0 : return aState->mSeenNonPunctuationSinceWhitespace;
8454 : }
8455 :
8456 : nsresult
8457 0 : nsFrame::CheckVisibility(nsPresContext* , int32_t , int32_t , bool , bool *, bool *)
8458 : {
8459 0 : return NS_ERROR_NOT_IMPLEMENTED;
8460 : }
8461 :
8462 :
8463 : int32_t
8464 0 : nsFrame::GetLineNumber(nsIFrame *aFrame, bool aLockScroll, nsIFrame** aContainingBlock)
8465 : {
8466 0 : NS_ASSERTION(aFrame, "null aFrame");
8467 0 : nsIFrame* blockFrame = aFrame;
8468 : nsIFrame* thisBlock;
8469 0 : nsAutoLineIterator it;
8470 0 : nsresult result = NS_ERROR_FAILURE;
8471 0 : while (NS_FAILED(result) && blockFrame)
8472 : {
8473 0 : thisBlock = blockFrame;
8474 0 : if (thisBlock->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
8475 : //if we are searching for a frame that is not in flow we will not find it.
8476 : //we must instead look for its placeholder
8477 0 : if (thisBlock->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
8478 : // abspos continuations don't have placeholders, get the fif
8479 0 : thisBlock = thisBlock->FirstInFlow();
8480 : }
8481 0 : thisBlock = thisBlock->GetPlaceholderFrame();
8482 0 : if (!thisBlock)
8483 0 : return -1;
8484 : }
8485 0 : blockFrame = thisBlock->GetParent();
8486 0 : result = NS_OK;
8487 0 : if (blockFrame) {
8488 0 : if (aLockScroll && blockFrame->IsScrollFrame())
8489 0 : return -1;
8490 0 : it = blockFrame->GetLineIterator();
8491 0 : if (!it)
8492 0 : result = NS_ERROR_FAILURE;
8493 : }
8494 : }
8495 0 : if (!blockFrame || !it)
8496 0 : return -1;
8497 :
8498 0 : if (aContainingBlock)
8499 0 : *aContainingBlock = blockFrame;
8500 0 : return it->FindLineContaining(thisBlock);
8501 : }
8502 :
8503 : nsresult
8504 0 : nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual,
8505 : bool aJumpLines, bool aScrollViewStop,
8506 : nsIFrame** aOutFrame, int32_t* aOutOffset,
8507 : bool* aOutJumpedLine, bool* aOutMovedOverNonSelectableText)
8508 : {
8509 : nsresult result;
8510 :
8511 0 : if (!aOutFrame || !aOutOffset || !aOutJumpedLine)
8512 0 : return NS_ERROR_NULL_POINTER;
8513 :
8514 0 : nsPresContext* presContext = PresContext();
8515 0 : *aOutFrame = nullptr;
8516 0 : *aOutOffset = 0;
8517 0 : *aOutJumpedLine = false;
8518 0 : *aOutMovedOverNonSelectableText = false;
8519 :
8520 : // Find the prev/next selectable frame
8521 0 : bool selectable = false;
8522 0 : nsIFrame *traversedFrame = this;
8523 0 : while (!selectable) {
8524 : nsIFrame *blockFrame;
8525 :
8526 0 : int32_t thisLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, &blockFrame);
8527 0 : if (thisLine < 0)
8528 0 : return NS_ERROR_FAILURE;
8529 :
8530 0 : nsAutoLineIterator it = blockFrame->GetLineIterator();
8531 0 : NS_ASSERTION(it, "GetLineNumber() succeeded but no block frame?");
8532 :
8533 : bool atLineEdge;
8534 : nsIFrame *firstFrame;
8535 : nsIFrame *lastFrame;
8536 0 : if (aVisual && presContext->BidiEnabled()) {
8537 0 : bool lineIsRTL = it->GetDirection();
8538 : bool isReordered;
8539 0 : result = it->CheckLineOrder(thisLine, &isReordered, &firstFrame, &lastFrame);
8540 0 : nsIFrame** framePtr = aDirection == eDirPrevious ? &firstFrame : &lastFrame;
8541 0 : if (*framePtr) {
8542 : bool frameIsRTL =
8543 0 : (nsBidiPresUtils::FrameDirection(*framePtr) == NSBIDI_RTL);
8544 0 : if ((frameIsRTL == lineIsRTL) == (aDirection == eDirPrevious)) {
8545 0 : nsFrame::GetFirstLeaf(presContext, framePtr);
8546 : } else {
8547 0 : nsFrame::GetLastLeaf(presContext, framePtr);
8548 : }
8549 0 : atLineEdge = *framePtr == traversedFrame;
8550 : } else {
8551 0 : atLineEdge = true;
8552 : }
8553 : } else {
8554 0 : nsRect nonUsedRect;
8555 : int32_t lineFrameCount;
8556 0 : result = it->GetLine(thisLine, &firstFrame, &lineFrameCount,
8557 0 : nonUsedRect);
8558 0 : if (NS_FAILED(result))
8559 0 : return result;
8560 :
8561 0 : if (aDirection == eDirPrevious) {
8562 0 : nsFrame::GetFirstLeaf(presContext, &firstFrame);
8563 0 : atLineEdge = firstFrame == traversedFrame;
8564 : } else { // eDirNext
8565 0 : lastFrame = firstFrame;
8566 0 : for (;lineFrameCount > 1;lineFrameCount --){
8567 0 : result = it->GetNextSiblingOnLine(lastFrame, thisLine);
8568 0 : if (NS_FAILED(result) || !lastFrame){
8569 0 : NS_ERROR("should not be reached nsFrame");
8570 0 : return NS_ERROR_FAILURE;
8571 : }
8572 : }
8573 0 : nsFrame::GetLastLeaf(presContext, &lastFrame);
8574 0 : atLineEdge = lastFrame == traversedFrame;
8575 : }
8576 : }
8577 :
8578 0 : if (atLineEdge) {
8579 0 : *aOutJumpedLine = true;
8580 0 : if (!aJumpLines)
8581 0 : return NS_ERROR_FAILURE; //we are done. cannot jump lines
8582 : }
8583 :
8584 0 : nsCOMPtr<nsIFrameEnumerator> frameTraversal;
8585 0 : result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal),
8586 : presContext, traversedFrame,
8587 : eLeaf,
8588 0 : aVisual && presContext->BidiEnabled(),
8589 : aScrollViewStop,
8590 : true, // aFollowOOFs
8591 : false // aSkipPopupChecks
8592 0 : );
8593 0 : if (NS_FAILED(result))
8594 0 : return result;
8595 :
8596 0 : if (aDirection == eDirNext)
8597 0 : frameTraversal->Next();
8598 : else
8599 0 : frameTraversal->Prev();
8600 :
8601 0 : traversedFrame = frameTraversal->CurrentItem();
8602 :
8603 : // Skip anonymous elements, but watch out for generated content
8604 0 : if (!traversedFrame ||
8605 0 : (!traversedFrame->IsGeneratedContentFrame() &&
8606 0 : traversedFrame->GetContent()->IsRootOfNativeAnonymousSubtree())) {
8607 0 : return NS_ERROR_FAILURE;
8608 : }
8609 :
8610 : // Skip brFrames, but only if they are not the only frame in the line
8611 0 : if (atLineEdge && aDirection == eDirPrevious &&
8612 0 : traversedFrame->IsBrFrame()) {
8613 : int32_t lineFrameCount;
8614 : nsIFrame *currentBlockFrame, *currentFirstFrame;
8615 0 : nsRect usedRect;
8616 0 : int32_t currentLine = nsFrame::GetLineNumber(traversedFrame, aScrollViewStop, ¤tBlockFrame);
8617 0 : nsAutoLineIterator iter = currentBlockFrame->GetLineIterator();
8618 0 : result = iter->GetLine(currentLine, ¤tFirstFrame, &lineFrameCount, usedRect);
8619 0 : if (NS_FAILED(result)) {
8620 0 : return result;
8621 : }
8622 0 : if (lineFrameCount > 1) {
8623 0 : continue;
8624 : }
8625 : }
8626 :
8627 0 : selectable = traversedFrame->IsSelectable(nullptr);
8628 0 : if (!selectable) {
8629 0 : *aOutMovedOverNonSelectableText = true;
8630 : }
8631 : } // while (!selectable)
8632 :
8633 0 : *aOutOffset = (aDirection == eDirNext) ? 0 : -1;
8634 :
8635 0 : if (aVisual && IsReversedDirectionFrame(traversedFrame)) {
8636 : // The new frame is reverse-direction, go to the other end
8637 0 : *aOutOffset = -1 - *aOutOffset;
8638 : }
8639 0 : *aOutFrame = traversedFrame;
8640 0 : return NS_OK;
8641 : }
8642 :
8643 950 : nsView* nsIFrame::GetClosestView(nsPoint* aOffset) const
8644 : {
8645 950 : nsPoint offset(0,0);
8646 1468 : for (const nsIFrame *f = this; f; f = f->GetParent()) {
8647 1468 : if (f->HasView()) {
8648 950 : if (aOffset)
8649 34 : *aOffset = offset;
8650 950 : return f->GetView();
8651 : }
8652 518 : offset += f->GetPosition();
8653 : }
8654 :
8655 0 : NS_NOTREACHED("No view on any parent? How did that happen?");
8656 0 : return nullptr;
8657 : }
8658 :
8659 :
8660 : /* virtual */ void
8661 0 : nsFrame::ChildIsDirty(nsIFrame* aChild)
8662 : {
8663 0 : NS_NOTREACHED("should never be called on a frame that doesn't inherit from "
8664 : "nsContainerFrame");
8665 0 : }
8666 :
8667 :
8668 : #ifdef ACCESSIBILITY
8669 : a11y::AccType
8670 0 : nsFrame::AccessibleType()
8671 : {
8672 0 : if (IsTableCaption() && !GetRect().IsEmpty()) {
8673 0 : return a11y::eHTMLCaptionType;
8674 : }
8675 0 : return a11y::eNoType;
8676 : }
8677 : #endif
8678 :
8679 : bool
8680 1406 : nsIFrame::ClearOverflowRects()
8681 : {
8682 1406 : if (mOverflow.mType == NS_FRAME_OVERFLOW_NONE) {
8683 1400 : return false;
8684 : }
8685 6 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
8686 6 : DeleteProperty(OverflowAreasProperty());
8687 : }
8688 6 : mOverflow.mType = NS_FRAME_OVERFLOW_NONE;
8689 6 : return true;
8690 : }
8691 :
8692 : /** Set the overflowArea rect, storing it as deltas or a separate rect
8693 : * depending on its size in relation to the primary frame rect.
8694 : */
8695 : bool
8696 313 : nsIFrame::SetOverflowAreas(const nsOverflowAreas& aOverflowAreas)
8697 : {
8698 313 : if (mOverflow.mType == NS_FRAME_OVERFLOW_LARGE) {
8699 216 : nsOverflowAreas* overflow = GetOverflowAreasProperty();
8700 216 : bool changed = *overflow != aOverflowAreas;
8701 216 : *overflow = aOverflowAreas;
8702 :
8703 : // Don't bother with converting to the deltas form if we already
8704 : // have a property.
8705 216 : return changed;
8706 : }
8707 :
8708 97 : const nsRect& vis = aOverflowAreas.VisualOverflow();
8709 97 : uint32_t l = -vis.x, // left edge: positive delta is leftwards
8710 97 : t = -vis.y, // top: positive is upwards
8711 97 : r = vis.XMost() - mRect.width, // right: positive is rightwards
8712 97 : b = vis.YMost() - mRect.height; // bottom: positive is downwards
8713 313 : if (aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) &&
8714 18 : l <= NS_FRAME_OVERFLOW_DELTA_MAX &&
8715 11 : t <= NS_FRAME_OVERFLOW_DELTA_MAX &&
8716 11 : r <= NS_FRAME_OVERFLOW_DELTA_MAX &&
8717 302 : b <= NS_FRAME_OVERFLOW_DELTA_MAX &&
8718 : // we have to check these against zero because we *never* want to
8719 : // set a frame as having no overflow in this function. This is
8720 : // because FinishAndStoreOverflow calls this function prior to
8721 : // SetRect based on whether the overflow areas match aNewSize.
8722 : // In the case where the overflow areas exactly match mRect but
8723 : // do not match aNewSize, we need to store overflow in a property
8724 : // so that our eventual SetRect/SetSize will know that it has to
8725 : // reset our overflow areas.
8726 11 : (l | t | r | b) != 0) {
8727 11 : VisualDeltas oldDeltas = mOverflow.mVisualDeltas;
8728 : // It's a "small" overflow area so we store the deltas for each edge
8729 : // directly in the frame, rather than allocating a separate rect.
8730 : // If they're all zero, that's fine; we're setting things to
8731 : // no-overflow.
8732 11 : mOverflow.mVisualDeltas.mLeft = l;
8733 11 : mOverflow.mVisualDeltas.mTop = t;
8734 11 : mOverflow.mVisualDeltas.mRight = r;
8735 11 : mOverflow.mVisualDeltas.mBottom = b;
8736 : // There was no scrollable overflow before, and there isn't now.
8737 11 : return oldDeltas != mOverflow.mVisualDeltas;
8738 : } else {
8739 280 : bool changed = !aOverflowAreas.ScrollableOverflow().IsEqualEdges(nsRect(nsPoint(0, 0), GetSize())) ||
8740 108 : !aOverflowAreas.VisualOverflow().IsEqualEdges(GetVisualOverflowFromDeltas());
8741 :
8742 : // it's a large overflow area that we need to store as a property
8743 86 : mOverflow.mType = NS_FRAME_OVERFLOW_LARGE;
8744 86 : AddProperty(OverflowAreasProperty(), new nsOverflowAreas(aOverflowAreas));
8745 86 : return changed;
8746 : }
8747 : }
8748 :
8749 : /**
8750 : * Compute the union of the border boxes of aFrame and its descendants,
8751 : * in aFrame's coordinate space (if aApplyTransform is false) or its
8752 : * post-transform coordinate space (if aApplyTransform is true).
8753 : */
8754 : static nsRect
8755 0 : UnionBorderBoxes(nsIFrame* aFrame, bool aApplyTransform,
8756 : bool& aOutValid,
8757 : const nsSize* aSizeOverride = nullptr,
8758 : const nsOverflowAreas* aOverflowOverride = nullptr)
8759 : {
8760 0 : const nsRect bounds(nsPoint(0, 0),
8761 0 : aSizeOverride ? *aSizeOverride : aFrame->GetSize());
8762 :
8763 : // The SVG container frames besides SVGTextFrame do not maintain
8764 : // an accurate mRect. It will make the outline be larger than
8765 : // we expect, we need to make them narrow to their children's outline.
8766 : // aOutValid is set to false if the returned nsRect is not valid
8767 : // and should not be included in the outline rectangle.
8768 0 : aOutValid = !(aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
8769 0 : !aFrame->IsFrameOfType(nsIFrame::eSVGContainer) ||
8770 0 : aFrame->IsSVGTextFrame();
8771 :
8772 0 : nsRect u;
8773 :
8774 0 : if (!aFrame->FrameMaintainsOverflow()) {
8775 0 : return u;
8776 : }
8777 :
8778 : // Start from our border-box, transformed. See comment below about
8779 : // transform of children.
8780 0 : bool doTransform = aApplyTransform && aFrame->IsTransformed();
8781 0 : if (doTransform) {
8782 0 : u = nsDisplayTransform::TransformRect(bounds, aFrame, &bounds);
8783 : } else {
8784 0 : u = bounds;
8785 : }
8786 :
8787 : // Only iterate through the children if the overflow areas suggest
8788 : // that we might need to, and if the frame doesn't clip its overflow
8789 : // anyway.
8790 0 : if (aOverflowOverride) {
8791 0 : if (!doTransform &&
8792 0 : bounds.IsEqualEdges(aOverflowOverride->VisualOverflow()) &&
8793 0 : bounds.IsEqualEdges(aOverflowOverride->ScrollableOverflow())) {
8794 0 : return u;
8795 : }
8796 : } else {
8797 0 : if (!doTransform &&
8798 0 : bounds.IsEqualEdges(aFrame->GetVisualOverflowRect()) &&
8799 0 : bounds.IsEqualEdges(aFrame->GetScrollableOverflowRect())) {
8800 0 : return u;
8801 : }
8802 : }
8803 0 : const nsStyleDisplay* disp = aFrame->StyleDisplay();
8804 0 : LayoutFrameType fType = aFrame->Type();
8805 0 : if (nsFrame::ShouldApplyOverflowClipping(aFrame, disp) ||
8806 0 : fType == LayoutFrameType::Scroll ||
8807 0 : fType == LayoutFrameType::ListControl ||
8808 : fType == LayoutFrameType::SVGOuterSVG) {
8809 0 : return u;
8810 : }
8811 :
8812 0 : const nsStyleEffects* effects = aFrame->StyleEffects();
8813 : Maybe<nsRect> clipPropClipRect =
8814 0 : aFrame->GetClipPropClipRect(disp, effects, bounds.Size());
8815 :
8816 : // Iterate over all children except pop-ups.
8817 : const nsIFrame::ChildListIDs skip(nsIFrame::kPopupList |
8818 0 : nsIFrame::kSelectPopupList);
8819 0 : for (nsIFrame::ChildListIterator childLists(aFrame);
8820 0 : !childLists.IsDone(); childLists.Next()) {
8821 0 : if (skip.Contains(childLists.CurrentID())) {
8822 0 : continue;
8823 : }
8824 :
8825 0 : nsFrameList children = childLists.CurrentList();
8826 0 : for (nsFrameList::Enumerator e(children); !e.AtEnd(); e.Next()) {
8827 0 : nsIFrame* child = e.get();
8828 : // Note that passing |true| for aApplyTransform when
8829 : // child->Combines3DTransformWithAncestors() is incorrect if our
8830 : // aApplyTransform is false... but the opposite would be as
8831 : // well. This is because elements within a preserve-3d scene
8832 : // are always transformed up to the top of the scene. This
8833 : // means we don't have a mechanism for getting a transform up to
8834 : // an intermediate point within the scene. We choose to
8835 : // over-transform rather than under-transform because this is
8836 : // consistent with other overflow areas.
8837 0 : bool validRect = true;
8838 0 : nsRect childRect = UnionBorderBoxes(child, true, validRect) +
8839 0 : child->GetPosition();
8840 :
8841 0 : if (!validRect) {
8842 0 : continue;
8843 : }
8844 :
8845 0 : if (clipPropClipRect) {
8846 : // Intersect with the clip before transforming.
8847 0 : childRect.IntersectRect(childRect, *clipPropClipRect);
8848 : }
8849 :
8850 : // Note that we transform each child separately according to
8851 : // aFrame's transform, and then union, which gives a different
8852 : // (smaller) result from unioning and then transforming the
8853 : // union. This doesn't match the way we handle overflow areas
8854 : // with 2-D transforms, though it does match the way we handle
8855 : // overflow areas in preserve-3d 3-D scenes.
8856 0 : if (doTransform && !child->Combines3DTransformWithAncestors()) {
8857 0 : childRect = nsDisplayTransform::TransformRect(childRect, aFrame, &bounds);
8858 : }
8859 :
8860 : // If a SVGContainer has a non-SVGContainer child, we assign
8861 : // its child's outline to this SVGContainer directly.
8862 0 : if (!aOutValid && validRect) {
8863 0 : u = childRect;
8864 0 : aOutValid = true;
8865 : } else {
8866 0 : u.UnionRectEdges(u, childRect);
8867 : }
8868 : }
8869 : }
8870 :
8871 0 : return u;
8872 : }
8873 :
8874 : static void
8875 1710 : ComputeAndIncludeOutlineArea(nsIFrame* aFrame, nsOverflowAreas& aOverflowAreas,
8876 : const nsSize& aNewSize)
8877 : {
8878 1710 : const nsStyleOutline* outline = aFrame->StyleOutline();
8879 1710 : if (!outline->ShouldPaintOutline()) {
8880 1710 : return;
8881 : }
8882 :
8883 : // When the outline property is set on a :-moz-block-inside-inline-wrapper
8884 : // pseudo-element, it inherited that outline from the inline that was broken
8885 : // because it contained a block. In that case, we don't want a really wide
8886 : // outline if the block inside the inline is narrow, so union the actual
8887 : // contents of the anonymous blocks.
8888 0 : nsIFrame *frameForArea = aFrame;
8889 0 : do {
8890 0 : nsIAtom *pseudoType = frameForArea->StyleContext()->GetPseudo();
8891 0 : if (pseudoType != nsCSSAnonBoxes::mozBlockInsideInlineWrapper)
8892 0 : break;
8893 : // If we're done, we really want it and all its later siblings.
8894 0 : frameForArea = frameForArea->PrincipalChildList().FirstChild();
8895 0 : NS_ASSERTION(frameForArea, "anonymous block with no children?");
8896 0 : } while (frameForArea);
8897 :
8898 : // Find the union of the border boxes of all descendants, or in
8899 : // the block-in-inline case, all descendants we care about.
8900 : //
8901 : // Note that the interesting perspective-related cases are taken
8902 : // care of by the code that handles those issues for overflow
8903 : // calling FinishAndStoreOverflow again, which in turn calls this
8904 : // function again. We still need to deal with preserve-3d a bit.
8905 0 : nsRect innerRect;
8906 : bool validRect;
8907 0 : if (frameForArea == aFrame) {
8908 0 : innerRect = UnionBorderBoxes(aFrame, false, validRect, &aNewSize, &aOverflowAreas);
8909 : } else {
8910 0 : for (; frameForArea; frameForArea = frameForArea->GetNextSibling()) {
8911 0 : nsRect r(UnionBorderBoxes(frameForArea, true, validRect));
8912 :
8913 : // Adjust for offsets transforms up to aFrame's pre-transform
8914 : // (i.e., normal) coordinate space; see comments in
8915 : // UnionBorderBoxes for some of the subtlety here.
8916 0 : for (nsIFrame *f = frameForArea, *parent = f->GetParent();
8917 : /* see middle of loop */;
8918 0 : f = parent, parent = f->GetParent()) {
8919 0 : r += f->GetPosition();
8920 0 : if (parent == aFrame) {
8921 0 : break;
8922 : }
8923 0 : if (parent->IsTransformed() && !f->Combines3DTransformWithAncestors()) {
8924 0 : r = nsDisplayTransform::TransformRect(r, parent);
8925 : }
8926 : }
8927 :
8928 0 : innerRect.UnionRect(innerRect, r);
8929 : }
8930 : }
8931 :
8932 : // Keep this code in sync with GetOutlineInnerRect in nsCSSRendering.cpp.
8933 0 : aFrame->SetProperty(nsIFrame::OutlineInnerRectProperty(),
8934 0 : new nsRect(innerRect));
8935 0 : const nscoord offset = outline->mOutlineOffset;
8936 0 : nsRect outerRect(innerRect);
8937 0 : bool useOutlineAuto = false;
8938 0 : if (nsLayoutUtils::IsOutlineStyleAutoEnabled()) {
8939 0 : useOutlineAuto = outline->mOutlineStyle == NS_STYLE_BORDER_STYLE_AUTO;
8940 0 : if (MOZ_UNLIKELY(useOutlineAuto)) {
8941 0 : nsPresContext* presContext = aFrame->PresContext();
8942 0 : nsITheme* theme = presContext->GetTheme();
8943 0 : if (theme && theme->ThemeSupportsWidget(presContext, aFrame,
8944 0 : NS_THEME_FOCUS_OUTLINE)) {
8945 0 : outerRect.Inflate(offset);
8946 0 : theme->GetWidgetOverflow(presContext->DeviceContext(), aFrame,
8947 0 : NS_THEME_FOCUS_OUTLINE, &outerRect);
8948 : } else {
8949 0 : useOutlineAuto = false;
8950 : }
8951 : }
8952 : }
8953 0 : if (MOZ_LIKELY(!useOutlineAuto)) {
8954 0 : nscoord width = outline->GetOutlineWidth();
8955 0 : outerRect.Inflate(width + offset);
8956 : }
8957 :
8958 0 : nsRect& vo = aOverflowAreas.VisualOverflow();
8959 0 : vo.UnionRectEdges(vo, innerRect.Union(outerRect));
8960 : }
8961 :
8962 : bool
8963 1710 : nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
8964 : nsSize aNewSize, nsSize* aOldSize,
8965 : const nsStyleDisplay* aStyleDisplay)
8966 : {
8967 1710 : MOZ_ASSERT(FrameMaintainsOverflow(),
8968 : "Don't call - overflow rects not maintained on these SVG frames");
8969 :
8970 1710 : const nsStyleDisplay* disp = StyleDisplayWithOptionalParam(aStyleDisplay);
8971 1710 : EffectSet* effectSet = EffectSet::GetEffectSet(this);
8972 1710 : bool hasTransform = IsTransformed(disp, effectSet);
8973 :
8974 3420 : nsRect bounds(nsPoint(0, 0), aNewSize);
8975 : // Store the passed in overflow area if we are a preserve-3d frame or we have
8976 : // a transform, and it's not just the frame bounds.
8977 1710 : if (hasTransform || Combines3DTransformWithAncestors(disp)) {
8978 84 : if (!aOverflowAreas.VisualOverflow().IsEqualEdges(bounds) ||
8979 17 : !aOverflowAreas.ScrollableOverflow().IsEqualEdges(bounds)) {
8980 : nsOverflowAreas* initial =
8981 50 : GetProperty(nsIFrame::InitialOverflowProperty());
8982 50 : if (!initial) {
8983 28 : AddProperty(nsIFrame::InitialOverflowProperty(),
8984 56 : new nsOverflowAreas(aOverflowAreas));
8985 22 : } else if (initial != &aOverflowAreas) {
8986 22 : *initial = aOverflowAreas;
8987 : }
8988 : } else {
8989 17 : DeleteProperty(nsIFrame::InitialOverflowProperty());
8990 : }
8991 : #ifdef DEBUG
8992 67 : SetProperty(nsIFrame::DebugInitialOverflowPropertyApplied(), true);
8993 : #endif
8994 : } else {
8995 : #ifdef DEBUG
8996 1643 : DeleteProperty(nsIFrame::DebugInitialOverflowPropertyApplied());
8997 : #endif
8998 : }
8999 :
9000 : // This is now called FinishAndStoreOverflow() instead of
9001 : // StoreOverflow() because frame-generic ways of adding overflow
9002 : // can happen here, e.g. CSS2 outline and native theme.
9003 : // If the overflow area width or height is nscoord_MAX, then a
9004 : // saturating union may have encounted an overflow, so the overflow may not
9005 : // contain the frame border-box. Don't warn in that case.
9006 : // Don't warn for SVG either, since SVG doesn't need the overflow area
9007 : // to contain the frame bounds.
9008 5130 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
9009 6840 : DebugOnly<nsRect*> r = &aOverflowAreas.Overflow(otype);
9010 3420 : NS_ASSERTION(aNewSize.width == 0 || aNewSize.height == 0 ||
9011 : r->width == nscoord_MAX || r->height == nscoord_MAX ||
9012 : (mState & NS_FRAME_SVG_LAYOUT) ||
9013 : r->Contains(nsRect(nsPoint(0,0), aNewSize)),
9014 : "Computed overflow area must contain frame bounds");
9015 : }
9016 :
9017 : // If we clip our children, clear accumulated overflow area. The
9018 : // children are actually clipped to the padding-box, but since the
9019 : // overflow area should include the entire border-box, just set it to
9020 : // the border-box here.
9021 1710 : NS_ASSERTION((disp->mOverflowY == NS_STYLE_OVERFLOW_CLIP) ==
9022 : (disp->mOverflowX == NS_STYLE_OVERFLOW_CLIP),
9023 : "If one overflow is clip, the other should be too");
9024 1710 : if (nsFrame::ShouldApplyOverflowClipping(this, disp)) {
9025 : // The contents are actually clipped to the padding area
9026 46 : aOverflowAreas.SetAllTo(bounds);
9027 : }
9028 :
9029 : // Overflow area must always include the frame's top-left and bottom-right,
9030 : // even if the frame rect is empty (so we can scroll to those positions).
9031 : // Pending a real fix for bug 426879, don't do this for inline frames
9032 : // with zero width.
9033 : // Do not do this for SVG either, since it will usually massively increase
9034 : // the area unnecessarily.
9035 3420 : if ((aNewSize.width != 0 || !IsInlineFrame()) &&
9036 1710 : !(GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
9037 4590 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
9038 3060 : nsRect& o = aOverflowAreas.Overflow(otype);
9039 3060 : o.UnionRectEdges(o, bounds);
9040 : }
9041 : }
9042 :
9043 : // Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background,
9044 : // so we add theme background overflow here so it's not clipped.
9045 1710 : if (!::IsXULBoxWrapped(this) && IsThemed(disp)) {
9046 190 : nsRect r(bounds);
9047 95 : nsPresContext *presContext = PresContext();
9048 190 : if (presContext->GetTheme()->
9049 95 : GetWidgetOverflow(presContext->DeviceContext(), this,
9050 95 : disp->mAppearance, &r)) {
9051 10 : nsRect& vo = aOverflowAreas.VisualOverflow();
9052 10 : vo.UnionRectEdges(vo, r);
9053 : }
9054 : }
9055 :
9056 1710 : ComputeAndIncludeOutlineArea(this, aOverflowAreas, aNewSize);
9057 :
9058 : // Nothing in here should affect scrollable overflow.
9059 3420 : aOverflowAreas.VisualOverflow() =
9060 3420 : ComputeEffectsRect(this, aOverflowAreas.VisualOverflow(), aNewSize);
9061 :
9062 : // Absolute position clipping
9063 1710 : const nsStyleEffects* effects = StyleEffects();
9064 : Maybe<nsRect> clipPropClipRect =
9065 3420 : GetClipPropClipRect(disp, effects, aNewSize);
9066 1710 : if (clipPropClipRect) {
9067 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
9068 0 : nsRect& o = aOverflowAreas.Overflow(otype);
9069 0 : o.IntersectRect(o, *clipPropClipRect);
9070 : }
9071 : }
9072 :
9073 : /* If we're transformed, transform the overflow rect by the current transformation. */
9074 1710 : nsSize oldSize = mRect.Size();
9075 1710 : bool sizeChanged = ((aOldSize ? *aOldSize : oldSize) != aNewSize);
9076 :
9077 : /* Since our size might not actually have been computed yet, we need to make sure that we use the
9078 : * correct dimensions by overriding the stored bounding rectangle with the value the caller has
9079 : * ensured us we'll use.
9080 : */
9081 1710 : SetSize(aNewSize);
9082 :
9083 1710 : if (ChildrenHavePerspective(disp) && sizeChanged) {
9084 0 : nsRect newBounds(nsPoint(0, 0), aNewSize);
9085 0 : RecomputePerspectiveChildrenOverflow(this, effectSet);
9086 : }
9087 :
9088 1710 : if (hasTransform) {
9089 67 : SetProperty(nsIFrame::PreTransformOverflowAreasProperty(),
9090 134 : new nsOverflowAreas(aOverflowAreas));
9091 :
9092 67 : if (Combines3DTransformWithAncestors(disp)) {
9093 : /* If we're a preserve-3d leaf frame, then our pre-transform overflow should be correct. Our
9094 : * post-transform overflow is empty though, because we only contribute to the overflow area
9095 : * of the preserve-3d root frame.
9096 : * If we're an intermediate frame then the pre-transform overflow should contain all our
9097 : * non-preserve-3d children, which is what we want. Again we have no post-transform overflow.
9098 : */
9099 0 : aOverflowAreas.SetAllTo(nsRect());
9100 : } else {
9101 201 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
9102 134 : nsRect& o = aOverflowAreas.Overflow(otype);
9103 134 : o = nsDisplayTransform::TransformRect(o, this);
9104 : }
9105 :
9106 : /* If we're the root of the 3d context, then we want to include the overflow areas of all
9107 : * the participants. This won't have happened yet as the code above set their overflow
9108 : * area to empty. Manually collect these overflow areas now.
9109 : */
9110 67 : if (Extend3DContext(disp, effectSet)) {
9111 0 : ComputePreserve3DChildrenOverflow(aOverflowAreas);
9112 : }
9113 : }
9114 : } else {
9115 1643 : DeleteProperty(nsIFrame::PreTransformOverflowAreasProperty());
9116 : }
9117 :
9118 : /* Revert the size change in case some caller is depending on this. */
9119 1710 : SetSize(oldSize);
9120 :
9121 : bool anyOverflowChanged;
9122 1710 : if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
9123 304 : anyOverflowChanged = SetOverflowAreas(aOverflowAreas);
9124 : } else {
9125 1406 : anyOverflowChanged = ClearOverflowRects();
9126 : }
9127 :
9128 1710 : if (anyOverflowChanged) {
9129 137 : nsSVGEffects::InvalidateDirectRenderingObservers(this);
9130 : }
9131 3420 : return anyOverflowChanged;
9132 : }
9133 :
9134 : void
9135 0 : nsIFrame::RecomputePerspectiveChildrenOverflow(const nsIFrame* aStartFrame,
9136 : EffectSet* aEffectSet)
9137 : {
9138 0 : nsIFrame::ChildListIterator lists(this);
9139 0 : for (; !lists.IsDone(); lists.Next()) {
9140 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
9141 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
9142 0 : nsIFrame* child = childFrames.get();
9143 0 : if (!child->FrameMaintainsOverflow()) {
9144 0 : continue; // frame does not maintain overflow rects
9145 : }
9146 0 : if (child->HasPerspective(aEffectSet)) {
9147 : nsOverflowAreas* overflow =
9148 0 : child->GetProperty(nsIFrame::InitialOverflowProperty());
9149 0 : nsRect bounds(nsPoint(0, 0), child->GetSize());
9150 0 : if (overflow) {
9151 0 : nsOverflowAreas overflowCopy = *overflow;
9152 0 : child->FinishAndStoreOverflow(overflowCopy, bounds.Size());
9153 : } else {
9154 0 : nsOverflowAreas boundsOverflow;
9155 0 : boundsOverflow.SetAllTo(bounds);
9156 0 : child->FinishAndStoreOverflow(boundsOverflow, bounds.Size());
9157 : }
9158 0 : } else if (child->GetContainingBlock(SKIP_SCROLLED_FRAME) == aStartFrame) {
9159 : // If a frame is using perspective, then the size used to compute
9160 : // perspective-origin is the size of the frame belonging to its parent
9161 : // style context. We must find any descendant frames using our size
9162 : // (by recursing into frames that have the same containing block)
9163 : // to update their overflow rects too.
9164 0 : child->RecomputePerspectiveChildrenOverflow(aStartFrame, aEffectSet);
9165 : }
9166 : }
9167 : }
9168 0 : }
9169 :
9170 : void
9171 0 : nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas)
9172 : {
9173 : // Find all descendants that participate in the 3d context, and include their overflow.
9174 : // These descendants have an empty overflow, so won't have been included in the normal
9175 : // overflow calculation. Any children that don't participate have normal overflow,
9176 : // so will have been included already.
9177 :
9178 0 : nsRect childVisual;
9179 0 : nsRect childScrollable;
9180 0 : nsIFrame::ChildListIterator lists(this);
9181 0 : for (; !lists.IsDone(); lists.Next()) {
9182 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
9183 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
9184 0 : nsIFrame* child = childFrames.get();
9185 :
9186 : // If this child participates in the 3d context, then take the pre-transform
9187 : // region (which contains all descendants that aren't participating in the 3d context)
9188 : // and transform it into the 3d context root coordinate space.
9189 0 : const nsStyleDisplay* childDisp = child->StyleDisplay();
9190 0 : if (child->Combines3DTransformWithAncestors(childDisp)) {
9191 0 : nsOverflowAreas childOverflow = child->GetOverflowAreasRelativeToSelf();
9192 :
9193 0 : NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
9194 0 : nsRect& o = childOverflow.Overflow(otype);
9195 0 : o = nsDisplayTransform::TransformRect(o, child);
9196 : }
9197 :
9198 0 : aOverflowAreas.UnionWith(childOverflow);
9199 :
9200 : // If this child also extends the 3d context, then recurse into it
9201 : // looking for more participants.
9202 0 : if (child->Extend3DContext(childDisp)) {
9203 0 : child->ComputePreserve3DChildrenOverflow(aOverflowAreas);
9204 : }
9205 : }
9206 : }
9207 : }
9208 0 : }
9209 :
9210 : uint32_t
9211 0 : nsIFrame::GetDepthInFrameTree() const
9212 : {
9213 0 : uint32_t result = 0;
9214 0 : for (nsContainerFrame* ancestor = GetParent(); ancestor;
9215 0 : ancestor = ancestor->GetParent()) {
9216 0 : result++;
9217 : }
9218 0 : return result;
9219 : }
9220 :
9221 : void
9222 205 : nsFrame::ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
9223 : nsIFrame* aChildFrame)
9224 : {
9225 410 : aOverflowAreas.UnionWith(aChildFrame->GetOverflowAreas() +
9226 615 : aChildFrame->GetPosition());
9227 205 : }
9228 :
9229 : /**
9230 : * This function takes a frame that is part of a block-in-inline split,
9231 : * and _if_ that frame is an anonymous block created by an ib split it
9232 : * returns the block's preceding inline. This is needed because the
9233 : * split inline's style context is the parent of the anonymous block's
9234 : * style context.
9235 : *
9236 : * If aFrame is not an anonymous block, null is returned.
9237 : */
9238 : static nsIFrame*
9239 0 : GetIBSplitSiblingForAnonymousBlock(const nsIFrame* aFrame)
9240 : {
9241 0 : NS_PRECONDITION(aFrame, "Must have a non-null frame!");
9242 0 : NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT,
9243 : "GetIBSplitSibling should only be called on ib-split frames");
9244 :
9245 0 : nsIAtom* type = aFrame->StyleContext()->GetPseudo();
9246 0 : if (type != nsCSSAnonBoxes::mozBlockInsideInlineWrapper) {
9247 : // it's not an anonymous block
9248 0 : return nullptr;
9249 : }
9250 :
9251 : // Find the first continuation of the frame. (Ugh. This ends up
9252 : // being O(N^2) when it is called O(N) times.)
9253 0 : aFrame = aFrame->FirstContinuation();
9254 :
9255 : /*
9256 : * Now look up the nsGkAtoms::IBSplitPrevSibling
9257 : * property.
9258 : */
9259 : nsIFrame *ibSplitSibling =
9260 0 : aFrame->GetProperty(nsIFrame::IBSplitPrevSibling());
9261 0 : NS_ASSERTION(ibSplitSibling, "Broken frame tree?");
9262 0 : return ibSplitSibling;
9263 : }
9264 :
9265 : /**
9266 : * Get the parent, corrected for the mangled frame tree resulting from
9267 : * having a block within an inline. The result only differs from the
9268 : * result of |GetParent| when |GetParent| returns an anonymous block
9269 : * that was created for an element that was 'display: inline' because
9270 : * that element contained a block.
9271 : *
9272 : * Also skip anonymous scrolled-content parents; inherit directly from the
9273 : * outer scroll frame.
9274 : *
9275 : * Also skip NAC parents if the child frame is NAC.
9276 : */
9277 : static nsIFrame*
9278 1541 : GetCorrectedParent(const nsIFrame* aFrame)
9279 : {
9280 1541 : nsIFrame* parent = aFrame->GetParent();
9281 1541 : if (!parent) {
9282 2 : return nullptr;
9283 : }
9284 :
9285 : // For a table caption we want the _inner_ table frame (unless it's anonymous)
9286 : // as the style parent.
9287 1539 : if (aFrame->IsTableCaption()) {
9288 0 : nsIFrame* innerTable = parent->PrincipalChildList().FirstChild();
9289 0 : if (!innerTable->StyleContext()->GetPseudo()) {
9290 0 : return innerTable;
9291 : }
9292 : }
9293 :
9294 : // Table wrappers are always anon boxes; if we're in here for an outer
9295 : // table, that actually means its the _inner_ table that wants to
9296 : // know its parent. So get the pseudo of the inner in that case.
9297 1539 : nsIAtom* pseudo = aFrame->StyleContext()->GetPseudo();
9298 1539 : if (pseudo == nsCSSAnonBoxes::tableWrapper) {
9299 0 : pseudo = aFrame->PrincipalChildList().FirstChild()->StyleContext()->GetPseudo();
9300 : }
9301 :
9302 : // Prevent NAC from inheriting NAC. This partially duplicates the logic
9303 : // implemented in nsCSSFrameConstructor::AddFCItemsForAnonymousContent, and is
9304 : // necessary so that restyle inherits style contexts in the same way as the
9305 : // initial styling performed in frame construction.
9306 : //
9307 : // It would be nice to put it in CorrectStyleParentFrame and therefore share
9308 : // it, but that would lose the information of whether the _child_ is NAC,
9309 : // since CorrectStyleParentFrame only knows about the prospective _parent_.
9310 : // This duplication and complexity will go away when we fully switch to the
9311 : // Servo style system, where all this can be handled much more naturally.
9312 : //
9313 : // We need to take special care not to disrupt the style inheritance of frames
9314 : // whose content is NAC but who implement a pseudo (like an anonymous
9315 : // box, or a non-NAC-backed pseudo like ::first-line) that does not match the
9316 : // one that the NAC implements, if any.
9317 1539 : nsIContent* content = aFrame->GetContent();
9318 : Element* element =
9319 1539 : content && content->IsElement() ? content->AsElement() : nullptr;
9320 1637 : if (element && element->IsNativeAnonymous() && !element->IsNativeScrollbarContent() &&
9321 98 : element->GetPseudoElementType() == aFrame->StyleContext()->GetPseudoType()) {
9322 52 : while (parent->GetContent() && parent->GetContent()->IsNativeAnonymous()) {
9323 0 : parent = parent->GetInFlowParent();
9324 : }
9325 : }
9326 :
9327 1539 : return nsFrame::CorrectStyleParentFrame(parent, pseudo);
9328 : }
9329 :
9330 : /* static */
9331 : nsIFrame*
9332 2834 : nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
9333 : nsIAtom* aChildPseudo)
9334 : {
9335 2834 : NS_PRECONDITION(aProspectiveParent, "Must have a prospective parent");
9336 :
9337 2834 : if (aChildPseudo) {
9338 : // Non-inheriting anon boxes have no style parent frame at all.
9339 459 : if (nsCSSAnonBoxes::IsNonInheritingAnonBox(aChildPseudo)) {
9340 117 : return nullptr;
9341 : }
9342 :
9343 : // Other anon boxes are parented to their actual parent already, except
9344 : // for non-elements. Those should not be treated as an anon box.
9345 627 : if (!nsCSSAnonBoxes::IsNonElement(aChildPseudo) &&
9346 285 : nsCSSAnonBoxes::IsAnonBox(aChildPseudo)) {
9347 113 : NS_ASSERTION(aChildPseudo != nsCSSAnonBoxes::mozBlockInsideInlineWrapper,
9348 : "Should have dealt with kids that have "
9349 : "NS_FRAME_PART_OF_IBSPLIT elsewhere");
9350 113 : return aProspectiveParent;
9351 : }
9352 : }
9353 :
9354 : // Otherwise, walk up out of all anon boxes. For placeholder frames, walk out
9355 : // of all pseudo-elements as well. Otherwise ReparentStyleContext could cause
9356 : // style data to be out of sync with the frame tree.
9357 2604 : nsIFrame* parent = aProspectiveParent;
9358 488 : do {
9359 3092 : if (parent->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
9360 0 : nsIFrame* sibling = GetIBSplitSiblingForAnonymousBlock(parent);
9361 :
9362 0 : if (sibling) {
9363 : // |parent| was a block in an {ib} split; use the inline as
9364 : // |the style parent.
9365 0 : parent = sibling;
9366 : }
9367 : }
9368 :
9369 3092 : nsIAtom* parentPseudo = parent->StyleContext()->GetPseudo();
9370 6250 : if (!parentPseudo ||
9371 656 : (!nsCSSAnonBoxes::IsAnonBox(parentPseudo) &&
9372 : // nsPlaceholderFrame pases in nsGkAtoms::placeholderFrame for
9373 : // aChildPseudo (even though that's not a valid pseudo-type) just to
9374 : // trigger this behavior of walking up to the nearest non-pseudo
9375 : // ancestor.
9376 66 : aChildPseudo != nsGkAtoms::placeholderFrame)) {
9377 2568 : return parent;
9378 : }
9379 :
9380 524 : parent = parent->GetParent();
9381 524 : } while (parent);
9382 :
9383 36 : if (aProspectiveParent->StyleContext()->GetPseudo() ==
9384 : nsCSSAnonBoxes::viewportScroll) {
9385 : // aProspectiveParent is the scrollframe for a viewport
9386 : // and the kids are the anonymous scrollbars
9387 13 : return aProspectiveParent;
9388 : }
9389 :
9390 : // We can get here if the root element is absolutely positioned.
9391 : // We can't test for this very accurately, but it can only happen
9392 : // when the prospective parent is a canvas frame.
9393 23 : NS_ASSERTION(aProspectiveParent->IsCanvasFrame(),
9394 : "Should have found a parent before this");
9395 23 : return nullptr;
9396 : }
9397 :
9398 : nsStyleContext*
9399 1702 : nsFrame::DoGetParentStyleContext(nsIFrame** aProviderFrame) const
9400 : {
9401 1702 : *aProviderFrame = nullptr;
9402 :
9403 : // Handle display:contents and the root frame, when there's no parent frame
9404 : // to inherit from.
9405 1702 : if (MOZ_LIKELY(mContent)) {
9406 1700 : nsIContent* parentContent = mContent->GetFlattenedTreeParent();
9407 1700 : if (MOZ_LIKELY(parentContent)) {
9408 1658 : nsIAtom* pseudo = StyleContext()->GetPseudo();
9409 2241 : if (!pseudo || !mContent->IsElement() ||
9410 304 : (!nsCSSAnonBoxes::IsAnonBox(pseudo) &&
9411 : // Ensure that we don't return the display:contents style
9412 : // of the parent content for pseudos that have the same content
9413 : // as their primary frame (like -moz-list-bullets do):
9414 1921 : mContent->GetPrimaryFrame() == this) ||
9415 : /* if next is true then it's really a request for the table frame's
9416 : parent context, see nsTable[Outer]Frame::GetParentStyleContext. */
9417 222 : pseudo == nsCSSAnonBoxes::tableWrapper) {
9418 1436 : nsFrameManager* fm = PresContext()->FrameManager();
9419 1436 : nsStyleContext* sc = fm->GetDisplayContentsStyleFor(parentContent);
9420 1436 : if (MOZ_UNLIKELY(sc)) {
9421 0 : return sc;
9422 : }
9423 : }
9424 : } else {
9425 42 : if (!StyleContext()->GetPseudo()) {
9426 : // we're a frame for the root. We have no style context parent.
9427 34 : return nullptr;
9428 : }
9429 : }
9430 : }
9431 :
9432 1668 : if (!(mState & NS_FRAME_OUT_OF_FLOW)) {
9433 : /*
9434 : * If this frame is an anonymous block created when an inline with a block
9435 : * inside it got split, then the parent style context is on its preceding
9436 : * inline. We can get to it using GetIBSplitSiblingForAnonymousBlock.
9437 : */
9438 1541 : if (mState & NS_FRAME_PART_OF_IBSPLIT) {
9439 0 : nsIFrame* ibSplitSibling = GetIBSplitSiblingForAnonymousBlock(this);
9440 0 : if (ibSplitSibling) {
9441 0 : return (*aProviderFrame = ibSplitSibling)->StyleContext();
9442 : }
9443 : }
9444 :
9445 : // If this frame is one of the blocks that split an inline, we must
9446 : // return the "special" inline parent, i.e., the parent that this
9447 : // frame would have if we didn't mangle the frame structure.
9448 1541 : *aProviderFrame = GetCorrectedParent(this);
9449 1541 : return *aProviderFrame ? (*aProviderFrame)->StyleContext() : nullptr;
9450 : }
9451 :
9452 : // We're an out-of-flow frame. For out-of-flow frames, we must
9453 : // resolve underneath the placeholder's parent. The placeholder is
9454 : // reached from the first-in-flow.
9455 127 : nsPlaceholderFrame* placeholder = FirstInFlow()->GetPlaceholderFrame();
9456 127 : if (!placeholder) {
9457 0 : NS_NOTREACHED("no placeholder frame for out-of-flow frame");
9458 0 : *aProviderFrame = GetCorrectedParent(this);
9459 0 : return *aProviderFrame ? (*aProviderFrame)->StyleContext() : nullptr;
9460 : }
9461 127 : return placeholder->GetParentStyleContextForOutOfFlow(aProviderFrame);
9462 : }
9463 :
9464 : void
9465 0 : nsFrame::GetLastLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
9466 : {
9467 0 : if (!aFrame || !*aFrame)
9468 0 : return;
9469 0 : nsIFrame *child = *aFrame;
9470 : //if we are a block frame then go for the last line of 'this'
9471 : while (1){
9472 0 : child = child->PrincipalChildList().FirstChild();
9473 0 : if (!child)
9474 0 : return;//nothing to do
9475 : nsIFrame* siblingFrame;
9476 : nsIContent* content;
9477 : //ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
9478 : //see bug 278197 comment #12 #13 for details
9479 0 : while ((siblingFrame = child->GetNextSibling()) &&
9480 0 : (content = siblingFrame->GetContent()) &&
9481 0 : !content->IsRootOfNativeAnonymousSubtree())
9482 0 : child = siblingFrame;
9483 0 : *aFrame = child;
9484 0 : }
9485 : }
9486 :
9487 : void
9488 0 : nsFrame::GetFirstLeaf(nsPresContext* aPresContext, nsIFrame **aFrame)
9489 : {
9490 0 : if (!aFrame || !*aFrame)
9491 0 : return;
9492 0 : nsIFrame *child = *aFrame;
9493 : while (1){
9494 0 : child = child->PrincipalChildList().FirstChild();
9495 0 : if (!child)
9496 0 : return;//nothing to do
9497 0 : *aFrame = child;
9498 : }
9499 : }
9500 :
9501 : /* virtual */ bool
9502 3 : nsIFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse)
9503 : {
9504 3 : int32_t tabIndex = -1;
9505 3 : if (aTabIndex) {
9506 0 : *aTabIndex = -1; // Default for early return is not focusable
9507 : }
9508 3 : bool isFocusable = false;
9509 :
9510 12 : if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors() &&
9511 9 : StyleContext()->GetPseudo() != nsCSSAnonBoxes::anonymousFlexItem &&
9512 3 : StyleContext()->GetPseudo() != nsCSSAnonBoxes::anonymousGridItem) {
9513 3 : const nsStyleUserInterface* ui = StyleUserInterface();
9514 6 : if (ui->mUserFocus != StyleUserFocus::Ignore &&
9515 3 : ui->mUserFocus != StyleUserFocus::None) {
9516 : // Pass in default tabindex of -1 for nonfocusable and 0 for focusable
9517 3 : tabIndex = 0;
9518 : }
9519 3 : isFocusable = mContent->IsFocusable(&tabIndex, aWithMouse);
9520 6 : if (!isFocusable && !aWithMouse && IsScrollFrame() &&
9521 0 : mContent->IsHTMLElement() &&
9522 3 : !mContent->IsRootOfNativeAnonymousSubtree() && mContent->GetParent() &&
9523 0 : !mContent->HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
9524 : // Elements with scrollable view are focusable with script & tabbable
9525 : // Otherwise you couldn't scroll them with keyboard, which is
9526 : // an accessibility issue (e.g. Section 508 rules)
9527 : // However, we don't make them to be focusable with the mouse,
9528 : // because the extra focus outlines are considered unnecessarily ugly.
9529 : // When clicked on, the selection position within the element
9530 : // will be enough to make them keyboard scrollable.
9531 0 : nsIScrollableFrame *scrollFrame = do_QueryFrame(this);
9532 0 : if (scrollFrame &&
9533 0 : !scrollFrame->GetScrollbarStyles().IsHiddenInBothDirections() &&
9534 0 : !scrollFrame->GetScrollRange().IsEqualEdges(nsRect(0, 0, 0, 0))) {
9535 : // Scroll bars will be used for overflow
9536 0 : isFocusable = true;
9537 0 : tabIndex = 0;
9538 : }
9539 : }
9540 : }
9541 :
9542 3 : if (aTabIndex) {
9543 0 : *aTabIndex = tabIndex;
9544 : }
9545 3 : return isFocusable;
9546 : }
9547 :
9548 : /**
9549 : * @return true if this text frame ends with a newline character which is
9550 : * treated as preformatted. It should return false if this is not a text frame.
9551 : */
9552 : bool
9553 0 : nsIFrame::HasSignificantTerminalNewline() const
9554 : {
9555 0 : return false;
9556 : }
9557 :
9558 : static uint8_t
9559 0 : ConvertSVGDominantBaselineToVerticalAlign(uint8_t aDominantBaseline)
9560 : {
9561 : // Most of these are approximate mappings.
9562 0 : switch (aDominantBaseline) {
9563 : case NS_STYLE_DOMINANT_BASELINE_HANGING:
9564 : case NS_STYLE_DOMINANT_BASELINE_TEXT_BEFORE_EDGE:
9565 0 : return NS_STYLE_VERTICAL_ALIGN_TEXT_TOP;
9566 : case NS_STYLE_DOMINANT_BASELINE_TEXT_AFTER_EDGE:
9567 : case NS_STYLE_DOMINANT_BASELINE_IDEOGRAPHIC:
9568 0 : return NS_STYLE_VERTICAL_ALIGN_TEXT_BOTTOM;
9569 : case NS_STYLE_DOMINANT_BASELINE_CENTRAL:
9570 : case NS_STYLE_DOMINANT_BASELINE_MIDDLE:
9571 : case NS_STYLE_DOMINANT_BASELINE_MATHEMATICAL:
9572 0 : return NS_STYLE_VERTICAL_ALIGN_MIDDLE;
9573 : case NS_STYLE_DOMINANT_BASELINE_AUTO:
9574 : case NS_STYLE_DOMINANT_BASELINE_ALPHABETIC:
9575 0 : return NS_STYLE_VERTICAL_ALIGN_BASELINE;
9576 : case NS_STYLE_DOMINANT_BASELINE_USE_SCRIPT:
9577 : case NS_STYLE_DOMINANT_BASELINE_NO_CHANGE:
9578 : case NS_STYLE_DOMINANT_BASELINE_RESET_SIZE:
9579 : // These three should not simply map to 'baseline', but we don't
9580 : // support the complex baseline model that SVG 1.1 has and which
9581 : // css3-linebox now defines.
9582 0 : return NS_STYLE_VERTICAL_ALIGN_BASELINE;
9583 : default:
9584 0 : NS_NOTREACHED("unexpected aDominantBaseline value");
9585 0 : return NS_STYLE_VERTICAL_ALIGN_BASELINE;
9586 : }
9587 : }
9588 :
9589 : uint8_t
9590 75 : nsIFrame::VerticalAlignEnum() const
9591 : {
9592 75 : if (nsSVGUtils::IsInSVGTextSubtree(this)) {
9593 : uint8_t dominantBaseline;
9594 0 : for (const nsIFrame* frame = this; frame; frame = frame->GetParent()) {
9595 0 : dominantBaseline = frame->StyleSVGReset()->mDominantBaseline;
9596 0 : if (dominantBaseline != NS_STYLE_DOMINANT_BASELINE_AUTO ||
9597 0 : frame->IsSVGTextFrame()) {
9598 0 : break;
9599 : }
9600 : }
9601 0 : return ConvertSVGDominantBaselineToVerticalAlign(dominantBaseline);
9602 : }
9603 :
9604 75 : const nsStyleCoord& verticalAlign = StyleDisplay()->mVerticalAlign;
9605 75 : if (verticalAlign.GetUnit() == eStyleUnit_Enumerated) {
9606 75 : return verticalAlign.GetIntValue();
9607 : }
9608 :
9609 0 : return eInvalidVerticalAlign;
9610 : }
9611 :
9612 : /* static */
9613 0 : void nsFrame::FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
9614 : nsIFrame::Cursor& aCursor)
9615 : {
9616 0 : aCursor.mCursor = ui->mCursor;
9617 0 : aCursor.mHaveHotspot = false;
9618 0 : aCursor.mLoading = false;
9619 0 : aCursor.mHotspotX = aCursor.mHotspotY = 0.0f;
9620 :
9621 0 : for (const nsCursorImage& item : ui->mCursorImages) {
9622 : uint32_t status;
9623 0 : imgRequestProxy* req = item.GetImage();
9624 0 : if (!req || NS_FAILED(req->GetImageStatus(&status))) {
9625 0 : continue;
9626 : }
9627 0 : if (!(status & imgIRequest::STATUS_LOAD_COMPLETE)) {
9628 : // If we are falling back because any cursor before is loading,
9629 : // let the consumer know.
9630 0 : aCursor.mLoading = true;
9631 0 : } else if (!(status & imgIRequest::STATUS_ERROR)) {
9632 : // This is the one we want
9633 0 : req->GetImage(getter_AddRefs(aCursor.mContainer));
9634 0 : aCursor.mHaveHotspot = item.mHaveHotspot;
9635 0 : aCursor.mHotspotX = item.mHotspotX;
9636 0 : aCursor.mHotspotY = item.mHotspotY;
9637 0 : break;
9638 : }
9639 : }
9640 0 : }
9641 :
9642 : NS_IMETHODIMP
9643 62 : nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
9644 : {
9645 : // XXXbz this comment needs some rewriting to make sense in the
9646 : // post-reflow-branch world.
9647 :
9648 : // Ok we need to compute our minimum, preferred, and maximum sizes.
9649 : // 1) Maximum size. This is easy. Its infinite unless it is overloaded by CSS.
9650 : // 2) Preferred size. This is a little harder. This is the size the block would be
9651 : // if it were laid out on an infinite canvas. So we can get this by reflowing
9652 : // the block with and INTRINSIC width and height. We can also do a nice optimization
9653 : // for incremental reflow. If the reflow is incremental then we can pass a flag to
9654 : // have the block compute the preferred width for us! Preferred height can just be
9655 : // the minimum height;
9656 : // 3) Minimum size. This is a toughy. We can pass the block a flag asking for the max element
9657 : // size. That would give us the width. Unfortunately you can only ask for a maxElementSize
9658 : // during an incremental reflow. So on other reflows we will just have to use 0.
9659 : // The min height on the other hand is fairly easy we need to get the largest
9660 : // line height. This can be done with the line iterator.
9661 :
9662 : // if we do have a rendering context
9663 62 : gfxContext* rendContext = aState.GetRenderingContext();
9664 62 : if (rendContext) {
9665 62 : nsPresContext* presContext = aState.PresContext();
9666 :
9667 : // If we don't have any HTML constraints and it's a resize, then nothing in the block
9668 : // could have changed, so no refresh is necessary.
9669 62 : nsBoxLayoutMetrics* metrics = BoxMetrics();
9670 62 : if (!DoesNeedRecalc(metrics->mBlockPrefSize))
9671 13 : return NS_OK;
9672 :
9673 : // the rect we plan to size to.
9674 98 : nsRect rect = GetRect();
9675 :
9676 49 : nsMargin bp(0,0,0,0);
9677 49 : GetXULBorderAndPadding(bp);
9678 :
9679 : {
9680 : // If we're a container for font size inflation, then shrink
9681 : // wrapping inside of us should not apply font size inflation.
9682 98 : AutoMaybeDisableFontInflation an(this);
9683 :
9684 49 : metrics->mBlockPrefSize.width =
9685 49 : GetPrefISize(rendContext) + bp.LeftRight();
9686 49 : metrics->mBlockMinSize.width =
9687 49 : GetMinISize(rendContext) + bp.LeftRight();
9688 : }
9689 :
9690 : // do the nasty.
9691 49 : const WritingMode wm = aState.OuterReflowInput() ?
9692 49 : aState.OuterReflowInput()->GetWritingMode() : GetWritingMode();
9693 98 : ReflowOutput desiredSize(wm);
9694 49 : BoxReflow(aState, presContext, desiredSize, rendContext,
9695 : rect.x, rect.y,
9696 49 : metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE);
9697 :
9698 49 : metrics->mBlockMinSize.height = 0;
9699 : // ok we need the max ascent of the items on the line. So to do this
9700 : // ask the block for its line iterator. Get the max ascent.
9701 98 : nsAutoLineIterator lines = GetLineIterator();
9702 49 : if (lines)
9703 : {
9704 12 : metrics->mBlockMinSize.height = 0;
9705 12 : int count = 0;
9706 12 : nsIFrame* firstFrame = nullptr;
9707 : int32_t framesOnLine;
9708 24 : nsRect lineBounds;
9709 :
9710 12 : do {
9711 24 : lines->GetLine(count, &firstFrame, &framesOnLine, lineBounds);
9712 :
9713 24 : if (lineBounds.height > metrics->mBlockMinSize.height)
9714 2 : metrics->mBlockMinSize.height = lineBounds.height;
9715 :
9716 24 : count++;
9717 24 : } while(firstFrame);
9718 : } else {
9719 37 : metrics->mBlockMinSize.height = desiredSize.Height();
9720 : }
9721 :
9722 49 : metrics->mBlockPrefSize.height = metrics->mBlockMinSize.height;
9723 :
9724 49 : if (desiredSize.BlockStartAscent() ==
9725 : ReflowOutput::ASK_FOR_BASELINE) {
9726 45 : if (!nsLayoutUtils::GetFirstLineBaseline(wm, this,
9727 : &metrics->mBlockAscent))
9728 43 : metrics->mBlockAscent = GetLogicalBaseline(wm);
9729 : } else {
9730 4 : metrics->mBlockAscent = desiredSize.BlockStartAscent();
9731 : }
9732 :
9733 : #ifdef DEBUG_adaptor
9734 : printf("min=(%d,%d), pref=(%d,%d), ascent=%d\n", metrics->mBlockMinSize.width,
9735 : metrics->mBlockMinSize.height,
9736 : metrics->mBlockPrefSize.width,
9737 : metrics->mBlockPrefSize.height,
9738 : metrics->mBlockAscent);
9739 : #endif
9740 : }
9741 :
9742 49 : return NS_OK;
9743 : }
9744 :
9745 : /* virtual */ nsILineIterator*
9746 37 : nsFrame::GetLineIterator()
9747 : {
9748 37 : return nullptr;
9749 : }
9750 :
9751 : nsSize
9752 168 : nsFrame::GetXULPrefSize(nsBoxLayoutState& aState)
9753 : {
9754 168 : nsSize size(0,0);
9755 336 : DISPLAY_PREF_SIZE(this, size);
9756 : // If the size is cached, and there are no HTML constraints that we might
9757 : // be depending on, then we just return the cached size.
9758 168 : nsBoxLayoutMetrics *metrics = BoxMetrics();
9759 168 : if (!DoesNeedRecalc(metrics->mPrefSize)) {
9760 150 : return metrics->mPrefSize;
9761 : }
9762 :
9763 18 : if (IsXULCollapsed())
9764 0 : return size;
9765 :
9766 : // get our size in CSS.
9767 : bool widthSet, heightSet;
9768 18 : bool completelyRedefined = nsIFrame::AddXULPrefSize(this, size, widthSet, heightSet);
9769 :
9770 : // Refresh our caches with new sizes.
9771 18 : if (!completelyRedefined) {
9772 18 : RefreshSizeCache(aState);
9773 18 : nsSize blockSize = metrics->mBlockPrefSize;
9774 :
9775 : // notice we don't need to add our borders or padding
9776 : // in. That's because the block did it for us.
9777 18 : if (!widthSet)
9778 18 : size.width = blockSize.width;
9779 18 : if (!heightSet)
9780 17 : size.height = blockSize.height;
9781 : }
9782 :
9783 18 : metrics->mPrefSize = size;
9784 18 : return size;
9785 : }
9786 :
9787 : nsSize
9788 146 : nsFrame::GetXULMinSize(nsBoxLayoutState& aState)
9789 : {
9790 146 : nsSize size(0,0);
9791 292 : DISPLAY_MIN_SIZE(this, size);
9792 : // Don't use the cache if we have HTMLReflowInput constraints --- they might have changed
9793 146 : nsBoxLayoutMetrics *metrics = BoxMetrics();
9794 146 : if (!DoesNeedRecalc(metrics->mMinSize)) {
9795 132 : size = metrics->mMinSize;
9796 132 : return size;
9797 : }
9798 :
9799 14 : if (IsXULCollapsed())
9800 0 : return size;
9801 :
9802 : // get our size in CSS.
9803 : bool widthSet, heightSet;
9804 : bool completelyRedefined =
9805 14 : nsIFrame::AddXULMinSize(aState, this, size, widthSet, heightSet);
9806 :
9807 : // Refresh our caches with new sizes.
9808 14 : if (!completelyRedefined) {
9809 13 : RefreshSizeCache(aState);
9810 13 : nsSize blockSize = metrics->mBlockMinSize;
9811 :
9812 13 : if (!widthSet)
9813 13 : size.width = blockSize.width;
9814 13 : if (!heightSet)
9815 13 : size.height = blockSize.height;
9816 : }
9817 :
9818 14 : metrics->mMinSize = size;
9819 14 : return size;
9820 : }
9821 :
9822 : nsSize
9823 152 : nsFrame::GetXULMaxSize(nsBoxLayoutState& aState)
9824 : {
9825 152 : nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
9826 304 : DISPLAY_MAX_SIZE(this, size);
9827 : // Don't use the cache if we have HTMLReflowInput constraints --- they might have changed
9828 152 : nsBoxLayoutMetrics *metrics = BoxMetrics();
9829 152 : if (!DoesNeedRecalc(metrics->mMaxSize)) {
9830 134 : size = metrics->mMaxSize;
9831 134 : return size;
9832 : }
9833 :
9834 18 : if (IsXULCollapsed())
9835 0 : return size;
9836 :
9837 18 : size = nsBox::GetXULMaxSize(aState);
9838 18 : metrics->mMaxSize = size;
9839 :
9840 18 : return size;
9841 : }
9842 :
9843 : nscoord
9844 284 : nsFrame::GetXULFlex()
9845 : {
9846 284 : nsBoxLayoutMetrics *metrics = BoxMetrics();
9847 284 : if (!DoesNeedRecalc(metrics->mFlex))
9848 236 : return metrics->mFlex;
9849 :
9850 48 : metrics->mFlex = nsBox::GetXULFlex();
9851 :
9852 48 : return metrics->mFlex;
9853 : }
9854 :
9855 : nscoord
9856 387 : nsFrame::GetXULBoxAscent(nsBoxLayoutState& aState)
9857 : {
9858 387 : nsBoxLayoutMetrics *metrics = BoxMetrics();
9859 387 : if (!DoesNeedRecalc(metrics->mAscent))
9860 356 : return metrics->mAscent;
9861 :
9862 31 : if (IsXULCollapsed()) {
9863 0 : metrics->mAscent = 0;
9864 : } else {
9865 : // Refresh our caches with new sizes.
9866 31 : RefreshSizeCache(aState);
9867 31 : metrics->mAscent = metrics->mBlockAscent;
9868 : }
9869 :
9870 31 : return metrics->mAscent;
9871 : }
9872 :
9873 : nsresult
9874 77 : nsFrame::DoXULLayout(nsBoxLayoutState& aState)
9875 : {
9876 154 : nsRect ourRect(mRect);
9877 :
9878 77 : gfxContext* rendContext = aState.GetRenderingContext();
9879 77 : nsPresContext* presContext = aState.PresContext();
9880 77 : WritingMode ourWM = GetWritingMode();
9881 77 : const WritingMode outerWM = aState.OuterReflowInput() ?
9882 77 : aState.OuterReflowInput()->GetWritingMode() : ourWM;
9883 154 : ReflowOutput desiredSize(outerWM);
9884 77 : LogicalSize ourSize = GetLogicalSize(outerWM);
9885 :
9886 77 : if (rendContext) {
9887 :
9888 77 : BoxReflow(aState, presContext, desiredSize, rendContext,
9889 77 : ourRect.x, ourRect.y, ourRect.width, ourRect.height);
9890 :
9891 77 : if (IsXULCollapsed()) {
9892 6 : SetSize(nsSize(0, 0));
9893 : } else {
9894 :
9895 : // if our child needs to be bigger. This might happend with
9896 : // wrapping text. There is no way to predict its height until we
9897 : // reflow it. Now that we know the height reshuffle upward.
9898 142 : if (desiredSize.ISize(outerWM) > ourSize.ISize(outerWM) ||
9899 71 : desiredSize.BSize(outerWM) > ourSize.BSize(outerWM)) {
9900 :
9901 : #ifdef DEBUG_GROW
9902 : XULDumpBox(stdout);
9903 : printf(" GREW from (%d,%d) -> (%d,%d)\n",
9904 : ourSize.ISize(outerWM), ourSize.BSize(outerWM),
9905 : desiredSize.ISize(outerWM), desiredSize.BSize(outerWM));
9906 : #endif
9907 :
9908 0 : if (desiredSize.ISize(outerWM) > ourSize.ISize(outerWM)) {
9909 0 : ourSize.ISize(outerWM) = desiredSize.ISize(outerWM);
9910 : }
9911 :
9912 0 : if (desiredSize.BSize(outerWM) > ourSize.BSize(outerWM)) {
9913 0 : ourSize.BSize(outerWM) = desiredSize.BSize(outerWM);
9914 : }
9915 : }
9916 :
9917 : // ensure our size is what we think is should be. Someone could have
9918 : // reset the frame to be smaller or something dumb like that.
9919 71 : SetSize(ourSize.ConvertTo(ourWM, outerWM));
9920 : }
9921 : }
9922 :
9923 : // Should we do this if IsXULCollapsed() is true?
9924 77 : LogicalSize size(GetLogicalSize(outerWM));
9925 77 : desiredSize.ISize(outerWM) = size.ISize(outerWM);
9926 77 : desiredSize.BSize(outerWM) = size.BSize(outerWM);
9927 77 : desiredSize.UnionOverflowAreasWithDesiredBounds();
9928 :
9929 77 : if (HasAbsolutelyPositionedChildren()) {
9930 : // Set up a |reflowInput| to pass into ReflowAbsoluteFrames
9931 : ReflowInput reflowInput(aState.PresContext(), this,
9932 : aState.GetRenderingContext(),
9933 0 : LogicalSize(ourWM, ISize(),
9934 : NS_UNCONSTRAINEDSIZE),
9935 0 : ReflowInput::DUMMY_PARENT_REFLOW_STATE);
9936 :
9937 0 : AddStateBits(NS_FRAME_IN_REFLOW);
9938 : // Set up a |reflowStatus| to pass into ReflowAbsoluteFrames
9939 : // (just a dummy value; hopefully that's OK)
9940 0 : nsReflowStatus reflowStatus;
9941 0 : ReflowAbsoluteFrames(aState.PresContext(), desiredSize,
9942 0 : reflowInput, reflowStatus);
9943 0 : RemoveStateBits(NS_FRAME_IN_REFLOW);
9944 : }
9945 :
9946 77 : nsSize oldSize(ourRect.Size());
9947 77 : FinishAndStoreOverflow(desiredSize.mOverflowAreas,
9948 77 : size.GetPhysicalSize(outerWM), &oldSize);
9949 :
9950 77 : SyncLayout(aState);
9951 :
9952 154 : return NS_OK;
9953 : }
9954 :
9955 : void
9956 126 : nsFrame::BoxReflow(nsBoxLayoutState& aState,
9957 : nsPresContext* aPresContext,
9958 : ReflowOutput& aDesiredSize,
9959 : gfxContext* aRenderingContext,
9960 : nscoord aX,
9961 : nscoord aY,
9962 : nscoord aWidth,
9963 : nscoord aHeight,
9964 : bool aMoveFrame)
9965 : {
9966 126 : DO_GLOBAL_REFLOW_COUNT("nsBoxToBlockAdaptor");
9967 :
9968 : #ifdef DEBUG_REFLOW
9969 : nsAdaptorAddIndents();
9970 : printf("Reflowing: ");
9971 : nsFrame::ListTag(stdout, mFrame);
9972 : printf("\n");
9973 : gIndent2++;
9974 : #endif
9975 :
9976 126 : nsBoxLayoutMetrics *metrics = BoxMetrics();
9977 126 : nsReflowStatus status;
9978 126 : WritingMode wm = aDesiredSize.GetWritingMode();
9979 :
9980 126 : bool needsReflow = NS_SUBTREE_DIRTY(this);
9981 :
9982 : // if we don't need a reflow then
9983 : // lets see if we are already that size. Yes? then don't even reflow. We are done.
9984 126 : if (!needsReflow) {
9985 :
9986 9 : if (aWidth != NS_INTRINSICSIZE && aHeight != NS_INTRINSICSIZE) {
9987 :
9988 : // if the new calculated size has a 0 width or a 0 height
9989 0 : if ((metrics->mLastSize.width == 0 || metrics->mLastSize.height == 0) && (aWidth == 0 || aHeight == 0)) {
9990 0 : needsReflow = false;
9991 0 : aDesiredSize.Width() = aWidth;
9992 0 : aDesiredSize.Height() = aHeight;
9993 0 : SetSize(aDesiredSize.Size(wm).ConvertTo(GetWritingMode(), wm));
9994 : } else {
9995 0 : aDesiredSize.Width() = metrics->mLastSize.width;
9996 0 : aDesiredSize.Height() = metrics->mLastSize.height;
9997 :
9998 : // remove the margin. The rect of our child does not include it but our calculated size does.
9999 : // don't reflow if we are already the right size
10000 0 : if (metrics->mLastSize.width == aWidth && metrics->mLastSize.height == aHeight)
10001 0 : needsReflow = false;
10002 : else
10003 0 : needsReflow = true;
10004 :
10005 : }
10006 : } else {
10007 : // if the width or height are intrinsic alway reflow because
10008 : // we don't know what it should be.
10009 9 : needsReflow = true;
10010 : }
10011 : }
10012 :
10013 : // ok now reflow the child into the spacers calculated space
10014 126 : if (needsReflow) {
10015 :
10016 126 : aDesiredSize.ClearSize();
10017 :
10018 : // create a reflow state to tell our child to flow at the given size.
10019 :
10020 : // Construct a bogus parent reflow state so that there's a usable
10021 : // containing block reflow state.
10022 126 : nsMargin margin(0,0,0,0);
10023 126 : GetXULMargin(margin);
10024 :
10025 126 : nsSize parentSize(aWidth, aHeight);
10026 126 : if (parentSize.height != NS_INTRINSICSIZE)
10027 77 : parentSize.height += margin.TopBottom();
10028 126 : if (parentSize.width != NS_INTRINSICSIZE)
10029 126 : parentSize.width += margin.LeftRight();
10030 :
10031 126 : nsIFrame *parentFrame = GetParent();
10032 126 : WritingMode parentWM = parentFrame->GetWritingMode();
10033 : ReflowInput
10034 : parentReflowInput(aPresContext, parentFrame, aRenderingContext,
10035 252 : LogicalSize(parentWM, parentSize),
10036 126 : ReflowInput::DUMMY_PARENT_REFLOW_STATE);
10037 :
10038 : // This may not do very much useful, but it's probably worth trying.
10039 126 : if (parentSize.width != NS_INTRINSICSIZE)
10040 126 : parentReflowInput.SetComputedWidth(std::max(parentSize.width, 0));
10041 126 : if (parentSize.height != NS_INTRINSICSIZE)
10042 77 : parentReflowInput.SetComputedHeight(std::max(parentSize.height, 0));
10043 126 : parentReflowInput.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
10044 : // XXX use box methods
10045 126 : parentFrame->GetXULPadding(parentReflowInput.ComputedPhysicalPadding());
10046 126 : parentFrame->GetXULBorder(parentReflowInput.ComputedPhysicalBorderPadding());
10047 126 : parentReflowInput.ComputedPhysicalBorderPadding() +=
10048 252 : parentReflowInput.ComputedPhysicalPadding();
10049 :
10050 : // Construct the parent chain manually since constructing it normally
10051 : // messes up dimensions.
10052 126 : const ReflowInput *outerReflowInput = aState.OuterReflowInput();
10053 126 : NS_ASSERTION(!outerReflowInput || outerReflowInput->mFrame != this,
10054 : "in and out of XUL on a single frame?");
10055 : const ReflowInput* parentRI;
10056 126 : if (outerReflowInput && outerReflowInput->mFrame == parentFrame) {
10057 : // We're a frame (such as a text control frame) that jumps into
10058 : // box reflow and then straight out of it on the child frame.
10059 : // This means we actually have a real parent reflow state.
10060 : // nsLayoutUtils::InflationMinFontSizeFor used to need this to be
10061 : // linked up correctly for text control frames, so do so here).
10062 0 : parentRI = outerReflowInput;
10063 : } else {
10064 126 : parentRI = &parentReflowInput;
10065 : }
10066 :
10067 : // XXX Is it OK that this reflow state has only one ancestor?
10068 : // (It used to have a bogus parent, skipping all the boxes).
10069 126 : WritingMode wm = GetWritingMode();
10070 126 : LogicalSize logicalSize(wm, nsSize(aWidth, aHeight));
10071 126 : logicalSize.BSize(wm) = NS_INTRINSICSIZE;
10072 : ReflowInput reflowInput(aPresContext, *parentRI, this,
10073 : logicalSize, nullptr,
10074 126 : ReflowInput::DUMMY_PARENT_REFLOW_STATE);
10075 :
10076 : // XXX_jwir3: This is somewhat fishy. If this is actually changing the value
10077 : // here (which it might be), then we should make sure that it's
10078 : // correct the first time around, rather than changing it later.
10079 126 : reflowInput.mCBReflowInput = parentRI;
10080 :
10081 126 : reflowInput.mReflowDepth = aState.GetReflowDepth();
10082 :
10083 : // mComputedWidth and mComputedHeight are content-box, not
10084 : // border-box
10085 126 : if (aWidth != NS_INTRINSICSIZE) {
10086 : nscoord computedWidth =
10087 126 : aWidth - reflowInput.ComputedPhysicalBorderPadding().LeftRight();
10088 126 : computedWidth = std::max(computedWidth, 0);
10089 126 : reflowInput.SetComputedWidth(computedWidth);
10090 : }
10091 :
10092 : // Most child frames of box frames (e.g. subdocument or scroll frames)
10093 : // need to be constrained to the provided size and overflow as necessary.
10094 : // The one exception are block frames, because we need to know their
10095 : // natural height excluding any overflow area which may be caused by
10096 : // various CSS effects such as shadow or outline.
10097 126 : if (!IsFrameOfType(eBlockFrame)) {
10098 97 : if (aHeight != NS_INTRINSICSIZE) {
10099 : nscoord computedHeight =
10100 60 : aHeight - reflowInput.ComputedPhysicalBorderPadding().TopBottom();
10101 60 : computedHeight = std::max(computedHeight, 0);
10102 60 : reflowInput.SetComputedHeight(computedHeight);
10103 : } else {
10104 37 : reflowInput.SetComputedHeight(
10105 74 : ComputeSize(aRenderingContext, wm,
10106 : logicalSize,
10107 37 : logicalSize.ISize(wm),
10108 74 : reflowInput.ComputedLogicalMargin().Size(wm),
10109 74 : reflowInput.ComputedLogicalBorderPadding().Size(wm) -
10110 74 : reflowInput.ComputedLogicalPadding().Size(wm),
10111 74 : reflowInput.ComputedLogicalPadding().Size(wm),
10112 111 : ComputeSizeFlags::eDefault).Height(wm));
10113 : }
10114 : }
10115 :
10116 : // Box layout calls SetRect before XULLayout, whereas non-box layout
10117 : // calls SetRect after Reflow.
10118 : // XXX Perhaps we should be doing this by twiddling the rect back to
10119 : // mLastSize before calling Reflow and then switching it back, but
10120 : // However, mLastSize can also be the size passed to BoxReflow by
10121 : // RefreshSizeCache, so that doesn't really make sense.
10122 126 : if (metrics->mLastSize.width != aWidth) {
10123 31 : reflowInput.SetHResize(true);
10124 :
10125 : // When font size inflation is enabled, a horizontal resize
10126 : // requires a full reflow. See ReflowInput::InitResizeFlags
10127 : // for more details.
10128 31 : if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
10129 0 : AddStateBits(NS_FRAME_IS_DIRTY);
10130 : }
10131 : }
10132 126 : if (metrics->mLastSize.height != aHeight) {
10133 65 : reflowInput.SetVResize(true);
10134 : }
10135 :
10136 : #ifdef DEBUG_REFLOW
10137 : nsAdaptorAddIndents();
10138 : printf("Size=(%d,%d)\n",reflowInput.ComputedWidth(),
10139 : reflowInput.ComputedHeight());
10140 : nsAdaptorAddIndents();
10141 : nsAdaptorPrintReason(reflowInput);
10142 : printf("\n");
10143 : #endif
10144 :
10145 : // place the child and reflow
10146 :
10147 126 : Reflow(aPresContext, aDesiredSize, reflowInput, status);
10148 :
10149 126 : NS_ASSERTION(status.IsComplete(), "bad status");
10150 :
10151 126 : uint32_t layoutFlags = aState.LayoutFlags();
10152 126 : nsContainerFrame::FinishReflowChild(this, aPresContext, aDesiredSize,
10153 126 : &reflowInput, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME);
10154 :
10155 : // Save the ascent. (bug 103925)
10156 126 : if (IsXULCollapsed()) {
10157 6 : metrics->mAscent = 0;
10158 : } else {
10159 120 : if (aDesiredSize.BlockStartAscent() ==
10160 : ReflowOutput::ASK_FOR_BASELINE) {
10161 102 : if (!nsLayoutUtils::GetFirstLineBaseline(wm, this, &metrics->mAscent))
10162 99 : metrics->mAscent = GetLogicalBaseline(wm);
10163 : } else
10164 18 : metrics->mAscent = aDesiredSize.BlockStartAscent();
10165 : }
10166 :
10167 : } else {
10168 0 : aDesiredSize.SetBlockStartAscent(metrics->mBlockAscent);
10169 : }
10170 :
10171 : #ifdef DEBUG_REFLOW
10172 : if (aHeight != NS_INTRINSICSIZE && aDesiredSize.Height() != aHeight)
10173 : {
10174 : nsAdaptorAddIndents();
10175 : printf("*****got taller!*****\n");
10176 :
10177 : }
10178 : if (aWidth != NS_INTRINSICSIZE && aDesiredSize.Width() != aWidth)
10179 : {
10180 : nsAdaptorAddIndents();
10181 : printf("*****got wider!******\n");
10182 :
10183 : }
10184 : #endif
10185 :
10186 126 : if (aWidth == NS_INTRINSICSIZE)
10187 0 : aWidth = aDesiredSize.Width();
10188 :
10189 126 : if (aHeight == NS_INTRINSICSIZE)
10190 49 : aHeight = aDesiredSize.Height();
10191 :
10192 126 : metrics->mLastSize.width = aDesiredSize.Width();
10193 126 : metrics->mLastSize.height = aDesiredSize.Height();
10194 :
10195 : #ifdef DEBUG_REFLOW
10196 : gIndent2--;
10197 : #endif
10198 126 : }
10199 :
10200 : nsBoxLayoutMetrics*
10201 1415 : nsFrame::BoxMetrics() const
10202 : {
10203 1415 : nsBoxLayoutMetrics* metrics = GetProperty(BoxMetricsProperty());
10204 1415 : NS_ASSERTION(metrics, "A box layout method was called but InitBoxMetrics was never called");
10205 1415 : return metrics;
10206 : }
10207 :
10208 : void
10209 0 : nsIFrame::UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
10210 : ServoRestyleState& aRestyleState)
10211 : {
10212 0 : MOZ_ASSERT(aChildFrame->GetParent() == this,
10213 : "This should only be used for children!");
10214 0 : MOZ_ASSERT(!GetContent() || !aChildFrame->GetContent() ||
10215 : aChildFrame->GetContent() == GetContent(),
10216 : "What content node is it a frame for?");
10217 0 : MOZ_ASSERT(!aChildFrame->GetPrevContinuation(),
10218 : "Only first continuations should end up here");
10219 :
10220 : // We could force the caller to pass in the pseudo, since some callers know it
10221 : // statically... But this API is a bit nicer.
10222 0 : nsIAtom* pseudo = aChildFrame->StyleContext()->GetPseudo();
10223 0 : MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(pseudo), "Child is not an anon box?");
10224 0 : MOZ_ASSERT(!nsCSSAnonBoxes::IsNonInheritingAnonBox(pseudo),
10225 : "Why did the caller bother calling us?");
10226 :
10227 : // Anon boxes inherit from their parent; that's us.
10228 : RefPtr<nsStyleContext> newContext =
10229 0 : aRestyleState.StyleSet().ResolveInheritingAnonymousBoxStyle(pseudo,
10230 0 : StyleContext());
10231 :
10232 : nsChangeHint childHint =
10233 0 : UpdateStyleOfOwnedChildFrame(aChildFrame, newContext, aRestyleState);
10234 :
10235 : // Now that we've updated the style on aChildFrame, check whether it itself
10236 : // has anon boxes to deal with.
10237 : ServoRestyleState childrenState(
10238 0 : *aChildFrame, aRestyleState, childHint, ServoRestyleState::Type::InFlow);
10239 0 : aChildFrame->UpdateStyleOfOwnedAnonBoxes(childrenState);
10240 :
10241 : // Assuming anon boxes don't have ::backdrop associated with them... if that
10242 : // ever changes, we'd need to handle that here, like we do in
10243 : // ServoRestyleManager::ProcessPostTraversal
10244 :
10245 : // We do need to handle block pseudo-elements here, though. Especially list
10246 : // bullets.
10247 0 : if (aChildFrame->IsFrameOfType(nsIFrame::eBlockFrame)) {
10248 0 : auto block = static_cast<nsBlockFrame*>(aChildFrame);
10249 0 : block->UpdatePseudoElementStyles(childrenState);
10250 : }
10251 0 : }
10252 :
10253 : /* static */ nsChangeHint
10254 0 : nsIFrame::UpdateStyleOfOwnedChildFrame(
10255 : nsIFrame* aChildFrame,
10256 : nsStyleContext* aNewStyleContext,
10257 : ServoRestyleState& aRestyleState,
10258 : const Maybe<nsStyleContext*>& aContinuationStyleContext)
10259 : {
10260 : // Figure out whether we have an actual change. It's important that we do
10261 : // this, for several reasons:
10262 : //
10263 : // 1) Even if all the child's changes are due to properties it inherits from
10264 : // us, it's possible that no one ever asked us for those style structs and
10265 : // hence changes to them aren't reflected in the changes handled at all.
10266 : //
10267 : // 2) Content can change stylesheets that change the styles of pseudos, and
10268 : // extensions can add/remove stylesheets that change the styles of
10269 : // anonymous boxes directly.
10270 : uint32_t equalStructs, samePointerStructs; // Not used, actually.
10271 0 : nsChangeHint childHint = aChildFrame->StyleContext()->CalcStyleDifference(
10272 : aNewStyleContext,
10273 : &equalStructs,
10274 0 : &samePointerStructs);
10275 : // If aChildFrame is out of flow, then aRestyleState's "changes handled by the
10276 : // parent" doesn't apply to it, because it may have some other parent in the
10277 : // frame tree.
10278 0 : if (!aChildFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
10279 0 : childHint = NS_RemoveSubsumedHints(
10280 0 : childHint, aRestyleState.ChangesHandledFor(*aChildFrame));
10281 : }
10282 0 : if (childHint) {
10283 0 : if (childHint & nsChangeHint_ReconstructFrame) {
10284 : // If we generate a reconstruct here, remove any non-reconstruct hints we
10285 : // may have already generated for this content.
10286 0 : aRestyleState.ChangeList().PopChangesForContent(
10287 0 : aChildFrame->GetContent());
10288 : }
10289 0 : aRestyleState.ChangeList().AppendChange(
10290 0 : aChildFrame, aChildFrame->GetContent(), childHint);
10291 : }
10292 :
10293 0 : aChildFrame->SetStyleContext(aNewStyleContext);
10294 : nsStyleContext* continuationStyle =
10295 0 : aContinuationStyleContext ? *aContinuationStyleContext : aNewStyleContext;
10296 0 : for (nsIFrame* kid = aChildFrame->GetNextContinuation();
10297 0 : kid;
10298 0 : kid = kid->GetNextContinuation()) {
10299 0 : kid->SetStyleContext(continuationStyle);
10300 : }
10301 :
10302 0 : return childHint;
10303 : }
10304 :
10305 : /* static */ void
10306 0 : nsIFrame::AddInPopupStateBitToDescendants(nsIFrame* aFrame)
10307 : {
10308 0 : if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) &&
10309 0 : aFrame->TrackingVisibility()) {
10310 : // Assume all frames in popups are visible.
10311 0 : aFrame->IncApproximateVisibleCount();
10312 : }
10313 :
10314 0 : aFrame->AddStateBits(NS_FRAME_IN_POPUP);
10315 :
10316 0 : AutoTArray<nsIFrame::ChildList,4> childListArray;
10317 0 : aFrame->GetCrossDocChildLists(&childListArray);
10318 :
10319 0 : nsIFrame::ChildListArrayIterator lists(childListArray);
10320 0 : for (; !lists.IsDone(); lists.Next()) {
10321 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
10322 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
10323 0 : AddInPopupStateBitToDescendants(childFrames.get());
10324 : }
10325 : }
10326 0 : }
10327 :
10328 : /* static */ void
10329 67 : nsIFrame::RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame)
10330 : {
10331 67 : if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) ||
10332 0 : nsLayoutUtils::IsPopup(aFrame)) {
10333 67 : return;
10334 : }
10335 :
10336 0 : aFrame->RemoveStateBits(NS_FRAME_IN_POPUP);
10337 :
10338 0 : if (aFrame->TrackingVisibility()) {
10339 : // We assume all frames in popups are visible, so this decrement balances
10340 : // out the increment in AddInPopupStateBitToDescendants above.
10341 0 : aFrame->DecApproximateVisibleCount();
10342 : }
10343 :
10344 0 : AutoTArray<nsIFrame::ChildList,4> childListArray;
10345 0 : aFrame->GetCrossDocChildLists(&childListArray);
10346 :
10347 0 : nsIFrame::ChildListArrayIterator lists(childListArray);
10348 0 : for (; !lists.IsDone(); lists.Next()) {
10349 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
10350 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
10351 0 : RemoveInPopupStateBitFromDescendants(childFrames.get());
10352 : }
10353 : }
10354 : }
10355 :
10356 : void
10357 67 : nsIFrame::SetParent(nsContainerFrame* aParent)
10358 : {
10359 : // Note that the current mParent may already be destroyed at this point.
10360 67 : mParent = aParent;
10361 67 : if (::IsXULBoxWrapped(this)) {
10362 7 : ::InitBoxMetrics(this, true);
10363 : } else {
10364 : // We could call Properties().Delete(BoxMetricsProperty()); here but
10365 : // that's kind of slow and re-parenting in such a way that we were
10366 : // IsXULBoxWrapped() before but not now should be very rare, so we'll just
10367 : // keep this unused frame property until this frame dies instead.
10368 : }
10369 :
10370 67 : if (GetStateBits() & (NS_FRAME_HAS_VIEW | NS_FRAME_HAS_CHILD_WITH_VIEW)) {
10371 14 : for (nsIFrame* f = aParent;
10372 7 : f && !(f->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW);
10373 : f = f->GetParent()) {
10374 0 : f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
10375 : }
10376 : }
10377 :
10378 67 : if (HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)) {
10379 0 : for (nsIFrame* f = aParent; f; f = f->GetParent()) {
10380 0 : if (f->HasAnyStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE)) {
10381 0 : break;
10382 : }
10383 0 : f->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
10384 : }
10385 : }
10386 :
10387 67 : if (HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
10388 0 : for (nsIFrame* f = aParent; f; f = f->GetParent()) {
10389 0 : if (f->HasAnyStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE)) {
10390 0 : break;
10391 : }
10392 0 : f->AddStateBits(NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE);
10393 : }
10394 : }
10395 :
10396 67 : if (HasInvalidFrameInSubtree()) {
10397 6 : for (nsIFrame* f = aParent;
10398 3 : f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT | NS_FRAME_IS_NONDISPLAY);
10399 : f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
10400 0 : f->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT);
10401 : }
10402 : }
10403 :
10404 67 : if (aParent->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
10405 0 : AddInPopupStateBitToDescendants(this);
10406 : } else {
10407 67 : RemoveInPopupStateBitFromDescendants(this);
10408 : }
10409 :
10410 : // If our new parent only has invalid children, then we just invalidate
10411 : // ourselves too. This is probably faster than clearing the flag all
10412 : // the way up the frame tree.
10413 67 : if (aParent->HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) {
10414 45 : InvalidateFrame();
10415 : }
10416 67 : }
10417 :
10418 : void
10419 954 : nsIFrame::CreateOwnLayerIfNeeded(nsDisplayListBuilder* aBuilder,
10420 : nsDisplayList* aList)
10421 : {
10422 2809 : if (GetContent() &&
10423 1792 : GetContent()->IsXULElement() &&
10424 838 : GetContent()->HasAttr(kNameSpaceID_None, nsGkAtoms::layer)) {
10425 56 : aList->AppendNewToTop(new (aBuilder)
10426 56 : nsDisplayOwnLayer(aBuilder, this, aList, aBuilder->CurrentActiveScrolledRoot()));
10427 : }
10428 954 : }
10429 :
10430 : bool
10431 2031 : nsIFrame::IsSelected() const
10432 : {
10433 2033 : return (GetContent() && GetContent()->IsSelectionDescendant()) ?
10434 2033 : IsFrameSelected() : false;
10435 : }
10436 :
10437 : /*static*/ void
10438 0 : nsIFrame::DestroyContentArray(ContentArray* aArray)
10439 : {
10440 0 : for (nsIContent* content : *aArray) {
10441 0 : content->UnbindFromTree();
10442 0 : NS_RELEASE(content);
10443 : }
10444 0 : delete aArray;
10445 0 : }
10446 :
10447 : bool
10448 0 : nsIFrame::IsPseudoStackingContextFromStyle() {
10449 : // If you change this, also change the computation of pseudoStackingContext
10450 : // in BuildDisplayListForChild()
10451 0 : if (StyleEffects()->mOpacity != 1.0f) {
10452 0 : return true;
10453 : }
10454 0 : const nsStyleDisplay* disp = StyleDisplay();
10455 0 : return disp->IsAbsPosContainingBlock(this) ||
10456 0 : disp->IsFloating(this) ||
10457 0 : (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT);
10458 : }
10459 :
10460 : Element*
10461 0 : nsIFrame::GetPseudoElement(CSSPseudoElementType aType)
10462 : {
10463 0 : if (!mContent) {
10464 0 : return nullptr;
10465 : }
10466 :
10467 0 : if (aType == CSSPseudoElementType::before) {
10468 0 : return nsLayoutUtils::GetBeforePseudo(mContent);
10469 : }
10470 :
10471 0 : if (aType == CSSPseudoElementType::after) {
10472 0 : return nsLayoutUtils::GetAfterPseudo(mContent);
10473 : }
10474 :
10475 0 : return nullptr;
10476 : }
10477 :
10478 : static bool
10479 4 : IsFrameScrolledOutOfView(nsIFrame *aFrame)
10480 : {
10481 : nsIScrollableFrame* scrollableFrame =
10482 : nsLayoutUtils::GetNearestScrollableFrame(aFrame,
10483 : nsLayoutUtils::SCROLLABLE_SAME_DOC |
10484 4 : nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN);
10485 4 : if (!scrollableFrame) {
10486 4 : return false;
10487 : }
10488 :
10489 0 : nsIFrame *scrollableParent = do_QueryFrame(scrollableFrame);
10490 0 : nsRect rect = aFrame->GetVisualOverflowRectRelativeToSelf();
10491 :
10492 : nsRect transformedRect =
10493 : nsLayoutUtils::TransformFrameRectToAncestor(aFrame,
10494 : rect,
10495 0 : scrollableParent);
10496 :
10497 0 : nsRect scrollableRect = scrollableParent->GetVisualOverflowRect();
10498 0 : if (!transformedRect.Intersects(scrollableRect)) {
10499 0 : return true;
10500 : }
10501 :
10502 0 : nsIFrame* parent = scrollableParent->GetParent();
10503 0 : if (!parent) {
10504 0 : return false;
10505 : }
10506 :
10507 0 : return IsFrameScrolledOutOfView(parent);
10508 : }
10509 :
10510 : bool
10511 4 : nsIFrame::IsScrolledOutOfView()
10512 : {
10513 4 : return IsFrameScrolledOutOfView(this);
10514 : }
10515 :
10516 : gfx::Matrix
10517 0 : nsIFrame::ComputeWidgetTransform()
10518 : {
10519 0 : const nsStyleUIReset* uiReset = StyleUIReset();
10520 0 : if (!uiReset->mSpecifiedWindowTransform) {
10521 0 : return gfx::Matrix();
10522 : }
10523 :
10524 0 : nsStyleTransformMatrix::TransformReferenceBox refBox;
10525 0 : refBox.Init(GetSize());
10526 :
10527 0 : nsPresContext* presContext = PresContext();
10528 0 : int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
10529 0 : RuleNodeCacheConditions dummy;
10530 : bool dummyBool;
10531 : gfx::Matrix4x4 matrix =
10532 0 : nsStyleTransformMatrix::ReadTransforms(uiReset->mSpecifiedWindowTransform->mHead,
10533 : StyleContext(),
10534 : presContext,
10535 : dummy,
10536 : refBox,
10537 : float(appUnitsPerDevPixel),
10538 0 : &dummyBool);
10539 :
10540 : // Apply the -moz-window-transform-origin translation to the matrix.
10541 : Point transformOrigin =
10542 : nsStyleTransformMatrix::Convert2DPosition(uiReset->mWindowTransformOrigin,
10543 0 : refBox, appUnitsPerDevPixel);
10544 0 : matrix.ChangeBasis(Point3D(transformOrigin.x, transformOrigin.y, 0));
10545 :
10546 0 : gfx::Matrix result2d;
10547 0 : if (!matrix.CanDraw2D(&result2d)) {
10548 : // FIXME: It would be preferable to reject non-2D transforms at parse time.
10549 : NS_WARNING("-moz-window-transform does not describe a 2D transform, "
10550 0 : "but only 2d transforms are supported");
10551 0 : return gfx::Matrix();
10552 : }
10553 :
10554 0 : return result2d;
10555 : }
10556 :
10557 : static already_AddRefed<nsIWidget>
10558 0 : GetWindowWidget(nsPresContext* aPresContext)
10559 : {
10560 : // We want to obtain the widget for the window. We can't use any of these
10561 : // methods: nsPresContext::GetRootWidget, nsPresContext::GetNearestWidget,
10562 : // nsIFrame::GetNearestWidget because those deal with child widgets and
10563 : // there is no parent widget connection between child widgets and the
10564 : // window widget that contains them.
10565 0 : nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
10566 0 : nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
10567 0 : if (!baseWindow) {
10568 0 : return nullptr;
10569 : }
10570 :
10571 0 : nsCOMPtr<nsIWidget> mainWidget;
10572 0 : baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
10573 0 : return mainWidget.forget();
10574 : }
10575 :
10576 : void
10577 0 : nsIFrame::UpdateWidgetProperties()
10578 : {
10579 0 : nsPresContext* presContext = PresContext();
10580 0 : if (presContext->IsRoot() || !presContext->IsChrome()) {
10581 : // Don't do anything for documents that aren't the root chrome document.
10582 0 : return;
10583 : }
10584 : nsIFrame* rootFrame =
10585 0 : presContext->FrameConstructor()->GetRootElementStyleFrame();
10586 0 : if (this != rootFrame) {
10587 : // Only the window's root style frame is relevant for widget properties.
10588 0 : return;
10589 : }
10590 0 : if (nsCOMPtr<nsIWidget> widget = GetWindowWidget(presContext)) {
10591 0 : widget->SetWindowOpacity(StyleUIReset()->mWindowOpacity);
10592 0 : widget->SetWindowTransform(ComputeWidgetTransform());
10593 : }
10594 : }
10595 :
10596 : void
10597 0 : nsIFrame::DoUpdateStyleOfOwnedAnonBoxes(ServoRestyleState& aRestyleState)
10598 : {
10599 : // As a special case, we check for {ib}-split block frames here, rather
10600 : // than have an nsInlineFrame::AppendDirectlyOwnedAnonBoxes implementation
10601 : // that returns them.
10602 : //
10603 : // (If we did handle them in AppendDirectlyOwnedAnonBoxes, we would have to
10604 : // return *all* of the in-flow {ib}-split block frames, not just the first
10605 : // one. For restyling, we really just need the first in flow, and the other
10606 : // user of the AppendOwnedAnonBoxes API, AllChildIterator, doesn't need to
10607 : // know about them at all, since these block frames never create NAC. So we
10608 : // avoid any unncessary hashtable lookups for the {ib}-split frames by calling
10609 : // UpdateStyleOfOwnedAnonBoxesForIBSplit directly here.)
10610 0 : if (IsInlineFrame()) {
10611 0 : if ((GetStateBits() & NS_FRAME_PART_OF_IBSPLIT)) {
10612 : static_cast<nsInlineFrame*>(this)->UpdateStyleOfOwnedAnonBoxesForIBSplit(
10613 0 : aRestyleState);
10614 : }
10615 0 : return;
10616 : }
10617 :
10618 0 : AutoTArray<OwnedAnonBox,4> frames;
10619 0 : AppendDirectlyOwnedAnonBoxes(frames);
10620 0 : for (OwnedAnonBox& box : frames) {
10621 0 : if (box.mUpdateStyleFn) {
10622 0 : box.mUpdateStyleFn(this, box.mAnonBoxFrame, aRestyleState);
10623 : } else {
10624 0 : UpdateStyleOfChildAnonBox(box.mAnonBoxFrame, aRestyleState);
10625 : }
10626 : }
10627 : }
10628 :
10629 : /* virtual */ void
10630 0 : nsIFrame::AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
10631 : {
10632 0 : MOZ_ASSERT(!(GetStateBits() & NS_FRAME_OWNS_ANON_BOXES));
10633 0 : MOZ_ASSERT(false, "Why did this get called?");
10634 : }
10635 :
10636 : void
10637 0 : nsIFrame::DoAppendOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult)
10638 : {
10639 0 : size_t i = aResult.Length();
10640 0 : AppendDirectlyOwnedAnonBoxes(aResult);
10641 :
10642 : // After appending the directly owned anonymous boxes of this frame to
10643 : // aResult above, we need to check each of them to see if they own
10644 : // any anonymous boxes themselves. Note that we keep progressing
10645 : // through aResult, looking for additional entries in aResult from these
10646 : // subsequent AppendDirectlyOwnedAnonBoxes calls. (Thus we can't
10647 : // use a ranged for loop here.)
10648 :
10649 0 : while (i < aResult.Length()) {
10650 0 : nsIFrame* f = aResult[i].mAnonBoxFrame;
10651 0 : if (f->GetStateBits() & NS_FRAME_OWNS_ANON_BOXES) {
10652 0 : f->AppendDirectlyOwnedAnonBoxes(aResult);
10653 : }
10654 0 : ++i;
10655 : }
10656 0 : }
10657 :
10658 0 : nsIFrame::CaretPosition::CaretPosition()
10659 0 : : mContentOffset(0)
10660 : {
10661 0 : }
10662 :
10663 0 : nsIFrame::CaretPosition::~CaretPosition()
10664 : {
10665 0 : }
10666 :
10667 : bool
10668 126 : nsFrame::HasCSSAnimations()
10669 : {
10670 : auto collection =
10671 126 : AnimationCollection<CSSAnimation>::GetAnimationCollection(this);
10672 126 : return collection && collection->mAnimations.Length() > 0;
10673 : }
10674 :
10675 : bool
10676 126 : nsFrame::HasCSSTransitions()
10677 : {
10678 : auto collection =
10679 126 : AnimationCollection<CSSTransition>::GetAnimationCollection(this);
10680 126 : return collection && collection->mAnimations.Length() > 0;
10681 : }
10682 :
10683 : size_t
10684 124 : nsIFrame::SizeOfFramePropertiesForTree(MallocSizeOf aMallocSizeOf) const
10685 : {
10686 124 : size_t result = 0;
10687 :
10688 124 : result += mProperties.SizeOfExcludingThis(aMallocSizeOf);
10689 :
10690 248 : FrameChildListIterator iter(this);
10691 330 : while (!iter.IsDone()) {
10692 206 : for (const nsIFrame* f : iter.CurrentList()) {
10693 103 : result += f->SizeOfFramePropertiesForTree(aMallocSizeOf);
10694 : }
10695 103 : iter.Next();
10696 : }
10697 :
10698 248 : return result;
10699 : }
10700 :
10701 : // Box layout debugging
10702 : #ifdef DEBUG_REFLOW
10703 : int32_t gIndent2 = 0;
10704 :
10705 : void
10706 : nsAdaptorAddIndents()
10707 : {
10708 : for(int32_t i=0; i < gIndent2; i++)
10709 : {
10710 : printf(" ");
10711 : }
10712 : }
10713 :
10714 : void
10715 : nsAdaptorPrintReason(ReflowInput& aReflowInput)
10716 : {
10717 : char* reflowReasonString;
10718 :
10719 : switch(aReflowInput.reason)
10720 : {
10721 : case eReflowReason_Initial:
10722 : reflowReasonString = "initial";
10723 : break;
10724 :
10725 : case eReflowReason_Resize:
10726 : reflowReasonString = "resize";
10727 : break;
10728 : case eReflowReason_Dirty:
10729 : reflowReasonString = "dirty";
10730 : break;
10731 : case eReflowReason_StyleChange:
10732 : reflowReasonString = "stylechange";
10733 : break;
10734 : case eReflowReason_Incremental:
10735 : {
10736 : switch (aReflowInput.reflowCommand->Type()) {
10737 : case eReflowType_StyleChanged:
10738 : reflowReasonString = "incremental (StyleChanged)";
10739 : break;
10740 : case eReflowType_ReflowDirty:
10741 : reflowReasonString = "incremental (ReflowDirty)";
10742 : break;
10743 : default:
10744 : reflowReasonString = "incremental (Unknown)";
10745 : }
10746 : }
10747 : break;
10748 : default:
10749 : reflowReasonString = "unknown";
10750 : break;
10751 : }
10752 :
10753 : printf("%s",reflowReasonString);
10754 : }
10755 :
10756 : #endif
10757 : #ifdef DEBUG_LAYOUT
10758 : void
10759 : nsFrame::GetBoxName(nsAutoString& aName)
10760 : {
10761 : GetFrameName(aName);
10762 : }
10763 : #endif
10764 :
10765 : #ifdef DEBUG
10766 : static void
10767 0 : GetTagName(nsFrame* aFrame, nsIContent* aContent, int aResultSize,
10768 : char* aResult)
10769 : {
10770 0 : if (aContent) {
10771 0 : snprintf(aResult, aResultSize, "%s@%p",
10772 0 : nsAtomCString(aContent->NodeInfo()->NameAtom()).get(), aFrame);
10773 : }
10774 : else {
10775 0 : snprintf(aResult, aResultSize, "@%p", aFrame);
10776 : }
10777 0 : }
10778 :
10779 : void
10780 111 : nsFrame::Trace(const char* aMethod, bool aEnter)
10781 : {
10782 111 : if (NS_FRAME_LOG_TEST(sFrameLogModule, NS_FRAME_TRACE_CALLS)) {
10783 : char tagbuf[40];
10784 0 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
10785 0 : printf_stderr("%s: %s %s", tagbuf, aEnter ? "enter" : "exit", aMethod);
10786 : }
10787 111 : }
10788 :
10789 : void
10790 111 : nsFrame::Trace(const char* aMethod, bool aEnter, nsReflowStatus aStatus)
10791 : {
10792 111 : if (NS_FRAME_LOG_TEST(sFrameLogModule, NS_FRAME_TRACE_CALLS)) {
10793 : char tagbuf[40];
10794 0 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
10795 0 : printf_stderr("%s: %s %s, status=%scomplete%s",
10796 : tagbuf, aEnter ? "enter" : "exit", aMethod,
10797 0 : aStatus.IsIncomplete() ? "not" : "",
10798 0 : (aStatus.NextInFlowNeedsReflow()) ? "+reflow" : "");
10799 : }
10800 111 : }
10801 :
10802 : void
10803 0 : nsFrame::TraceMsg(const char* aFormatString, ...)
10804 : {
10805 0 : if (NS_FRAME_LOG_TEST(sFrameLogModule, NS_FRAME_TRACE_CALLS)) {
10806 : // Format arguments into a buffer
10807 : char argbuf[200];
10808 : va_list ap;
10809 0 : va_start(ap, aFormatString);
10810 0 : VsprintfLiteral(argbuf, aFormatString, ap);
10811 0 : va_end(ap);
10812 :
10813 : char tagbuf[40];
10814 0 : GetTagName(this, mContent, sizeof(tagbuf), tagbuf);
10815 0 : printf_stderr("%s: %s", tagbuf, argbuf);
10816 : }
10817 0 : }
10818 :
10819 : void
10820 440 : nsFrame::VerifyDirtyBitSet(const nsFrameList& aFrameList)
10821 : {
10822 908 : for (nsFrameList::Enumerator e(aFrameList); !e.AtEnd(); e.Next()) {
10823 468 : NS_ASSERTION(e.get()->GetStateBits() & NS_FRAME_IS_DIRTY,
10824 : "dirty bit not set");
10825 : }
10826 440 : }
10827 :
10828 : // Start Display Reflow
10829 : #ifdef DEBUG
10830 :
10831 587 : DR_cookie::DR_cookie(nsPresContext* aPresContext,
10832 : nsIFrame* aFrame,
10833 : const ReflowInput& aReflowInput,
10834 : ReflowOutput& aMetrics,
10835 587 : nsReflowStatus& aStatus)
10836 587 : :mPresContext(aPresContext), mFrame(aFrame), mReflowInput(aReflowInput), mMetrics(aMetrics), mStatus(aStatus)
10837 : {
10838 587 : MOZ_COUNT_CTOR(DR_cookie);
10839 587 : mValue = nsFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowInput);
10840 587 : }
10841 :
10842 1174 : DR_cookie::~DR_cookie()
10843 : {
10844 587 : MOZ_COUNT_DTOR(DR_cookie);
10845 587 : nsFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue);
10846 587 : }
10847 :
10848 884 : DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame)
10849 884 : : mFrame(aFrame)
10850 : {
10851 884 : MOZ_COUNT_CTOR(DR_layout_cookie);
10852 884 : mValue = nsFrame::DisplayLayoutEnter(mFrame);
10853 884 : }
10854 :
10855 1768 : DR_layout_cookie::~DR_layout_cookie()
10856 : {
10857 884 : MOZ_COUNT_DTOR(DR_layout_cookie);
10858 884 : nsFrame::DisplayLayoutExit(mFrame, mValue);
10859 884 : }
10860 :
10861 608 : DR_intrinsic_width_cookie::DR_intrinsic_width_cookie(
10862 : nsIFrame* aFrame,
10863 : const char* aType,
10864 608 : nscoord& aResult)
10865 : : mFrame(aFrame)
10866 : , mType(aType)
10867 608 : , mResult(aResult)
10868 : {
10869 608 : MOZ_COUNT_CTOR(DR_intrinsic_width_cookie);
10870 608 : mValue = nsFrame::DisplayIntrinsicISizeEnter(mFrame, mType);
10871 608 : }
10872 :
10873 1216 : DR_intrinsic_width_cookie::~DR_intrinsic_width_cookie()
10874 : {
10875 608 : MOZ_COUNT_DTOR(DR_intrinsic_width_cookie);
10876 608 : nsFrame::DisplayIntrinsicISizeExit(mFrame, mType, mResult, mValue);
10877 608 : }
10878 :
10879 10263 : DR_intrinsic_size_cookie::DR_intrinsic_size_cookie(
10880 : nsIFrame* aFrame,
10881 : const char* aType,
10882 10263 : nsSize& aResult)
10883 : : mFrame(aFrame)
10884 : , mType(aType)
10885 10263 : , mResult(aResult)
10886 : {
10887 10263 : MOZ_COUNT_CTOR(DR_intrinsic_size_cookie);
10888 10263 : mValue = nsFrame::DisplayIntrinsicSizeEnter(mFrame, mType);
10889 10263 : }
10890 :
10891 20526 : DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie()
10892 : {
10893 10263 : MOZ_COUNT_DTOR(DR_intrinsic_size_cookie);
10894 10263 : nsFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue);
10895 10263 : }
10896 :
10897 652 : DR_init_constraints_cookie::DR_init_constraints_cookie(
10898 : nsIFrame* aFrame,
10899 : ReflowInput* aState,
10900 : nscoord aCBWidth,
10901 : nscoord aCBHeight,
10902 : const nsMargin* aMargin,
10903 652 : const nsMargin* aPadding)
10904 : : mFrame(aFrame)
10905 652 : , mState(aState)
10906 : {
10907 652 : MOZ_COUNT_CTOR(DR_init_constraints_cookie);
10908 652 : mValue = ReflowInput::DisplayInitConstraintsEnter(mFrame, mState,
10909 : aCBWidth, aCBHeight,
10910 : aMargin, aPadding);
10911 652 : }
10912 :
10913 1304 : DR_init_constraints_cookie::~DR_init_constraints_cookie()
10914 : {
10915 652 : MOZ_COUNT_DTOR(DR_init_constraints_cookie);
10916 652 : ReflowInput::DisplayInitConstraintsExit(mFrame, mState, mValue);
10917 652 : }
10918 :
10919 652 : DR_init_offsets_cookie::DR_init_offsets_cookie(
10920 : nsIFrame* aFrame,
10921 : SizeComputationInput* aState,
10922 : const LogicalSize& aPercentBasis,
10923 : WritingMode aCBWritingMode,
10924 : const nsMargin* aMargin,
10925 652 : const nsMargin* aPadding)
10926 : : mFrame(aFrame)
10927 652 : , mState(aState)
10928 : {
10929 652 : MOZ_COUNT_CTOR(DR_init_offsets_cookie);
10930 652 : mValue = SizeComputationInput::DisplayInitOffsetsEnter(mFrame, mState,
10931 : aPercentBasis,
10932 : aCBWritingMode,
10933 : aMargin, aPadding);
10934 652 : }
10935 :
10936 1304 : DR_init_offsets_cookie::~DR_init_offsets_cookie()
10937 : {
10938 652 : MOZ_COUNT_DTOR(DR_init_offsets_cookie);
10939 652 : SizeComputationInput::DisplayInitOffsetsExit(mFrame, mState, mValue);
10940 652 : }
10941 :
10942 652 : DR_init_type_cookie::DR_init_type_cookie(
10943 : nsIFrame* aFrame,
10944 652 : ReflowInput* aState)
10945 : : mFrame(aFrame)
10946 652 : , mState(aState)
10947 : {
10948 652 : MOZ_COUNT_CTOR(DR_init_type_cookie);
10949 652 : mValue = ReflowInput::DisplayInitFrameTypeEnter(mFrame, mState);
10950 652 : }
10951 :
10952 1304 : DR_init_type_cookie::~DR_init_type_cookie()
10953 : {
10954 652 : MOZ_COUNT_DTOR(DR_init_type_cookie);
10955 652 : ReflowInput::DisplayInitFrameTypeExit(mFrame, mState, mValue);
10956 652 : }
10957 :
10958 : struct DR_FrameTypeInfo;
10959 : struct DR_FrameTreeNode;
10960 : struct DR_Rule;
10961 :
10962 : struct DR_State
10963 : {
10964 : DR_State();
10965 : ~DR_State();
10966 : void Init();
10967 : void AddFrameTypeInfo(LayoutFrameType aFrameType,
10968 : const char* aFrameNameAbbrev,
10969 : const char* aFrameName);
10970 : DR_FrameTypeInfo* GetFrameTypeInfo(LayoutFrameType aFrameType);
10971 : DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName);
10972 : void InitFrameTypeTable();
10973 : DR_FrameTreeNode* CreateTreeNode(nsIFrame* aFrame,
10974 : const ReflowInput* aReflowInput);
10975 : void FindMatchingRule(DR_FrameTreeNode& aNode);
10976 : bool RuleMatches(DR_Rule& aRule,
10977 : DR_FrameTreeNode& aNode);
10978 : bool GetToken(FILE* aFile,
10979 : char* aBuf,
10980 : size_t aBufSize);
10981 : DR_Rule* ParseRule(FILE* aFile);
10982 : void ParseRulesFile();
10983 : void AddRule(nsTArray<DR_Rule*>& aRules,
10984 : DR_Rule& aRule);
10985 : bool IsWhiteSpace(int c);
10986 : bool GetNumber(char* aBuf,
10987 : int32_t& aNumber);
10988 : void PrettyUC(nscoord aSize,
10989 : char* aBuf,
10990 : int aBufSize);
10991 : void PrintMargin(const char* tag, const nsMargin* aMargin);
10992 : void DisplayFrameTypeInfo(nsIFrame* aFrame,
10993 : int32_t aIndent);
10994 : void DeleteTreeNode(DR_FrameTreeNode& aNode);
10995 :
10996 : bool mInited;
10997 : bool mActive;
10998 : int32_t mCount;
10999 : int32_t mAssert;
11000 : int32_t mIndent;
11001 : bool mIndentUndisplayedFrames;
11002 : bool mDisplayPixelErrors;
11003 : nsTArray<DR_Rule*> mWildRules;
11004 : nsTArray<DR_FrameTypeInfo> mFrameTypeTable;
11005 : // reflow specific state
11006 : nsTArray<DR_FrameTreeNode*> mFrameTreeLeaves;
11007 : };
11008 :
11009 : static DR_State *DR_state; // the one and only DR_State
11010 :
11011 : struct DR_RulePart
11012 : {
11013 0 : explicit DR_RulePart(LayoutFrameType aFrameType)
11014 0 : : mFrameType(aFrameType)
11015 0 : , mNext(0)
11016 0 : {}
11017 :
11018 : void Destroy();
11019 :
11020 : LayoutFrameType mFrameType;
11021 : DR_RulePart* mNext;
11022 : };
11023 :
11024 0 : void DR_RulePart::Destroy()
11025 : {
11026 0 : if (mNext) {
11027 0 : mNext->Destroy();
11028 : }
11029 : delete this;
11030 0 : }
11031 :
11032 : struct DR_Rule
11033 : {
11034 0 : DR_Rule() : mLength(0), mTarget(nullptr), mDisplay(false) {
11035 0 : MOZ_COUNT_CTOR(DR_Rule);
11036 0 : }
11037 0 : ~DR_Rule() {
11038 0 : if (mTarget) mTarget->Destroy();
11039 0 : MOZ_COUNT_DTOR(DR_Rule);
11040 0 : }
11041 : void AddPart(LayoutFrameType aFrameType);
11042 :
11043 : uint32_t mLength;
11044 : DR_RulePart* mTarget;
11045 : bool mDisplay;
11046 : };
11047 :
11048 : void
11049 0 : DR_Rule::AddPart(LayoutFrameType aFrameType)
11050 : {
11051 0 : DR_RulePart* newPart = new DR_RulePart(aFrameType);
11052 0 : newPart->mNext = mTarget;
11053 0 : mTarget = newPart;
11054 0 : mLength++;
11055 0 : }
11056 :
11057 70 : struct DR_FrameTypeInfo
11058 : {
11059 : DR_FrameTypeInfo(LayoutFrameType aFrameType,
11060 : const char* aFrameNameAbbrev,
11061 : const char* aFrameName);
11062 140 : ~DR_FrameTypeInfo() {
11063 : int32_t numElements;
11064 70 : numElements = mRules.Length();
11065 70 : for (int32_t i = numElements - 1; i >= 0; i--) {
11066 0 : delete mRules.ElementAt(i);
11067 : }
11068 70 : }
11069 :
11070 : LayoutFrameType mType;
11071 : char mNameAbbrev[16];
11072 : char mName[32];
11073 : nsTArray<DR_Rule*> mRules;
11074 : private:
11075 : DR_FrameTypeInfo& operator=(const DR_FrameTypeInfo&) = delete;
11076 : };
11077 :
11078 70 : DR_FrameTypeInfo::DR_FrameTypeInfo(LayoutFrameType aFrameType,
11079 : const char* aFrameNameAbbrev,
11080 70 : const char* aFrameName)
11081 : {
11082 70 : mType = aFrameType;
11083 70 : PL_strncpyz(mNameAbbrev, aFrameNameAbbrev, sizeof(mNameAbbrev));
11084 70 : PL_strncpyz(mName, aFrameName, sizeof(mName));
11085 70 : }
11086 :
11087 : struct DR_FrameTreeNode
11088 : {
11089 0 : DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent) : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0)
11090 : {
11091 0 : MOZ_COUNT_CTOR(DR_FrameTreeNode);
11092 0 : }
11093 :
11094 0 : ~DR_FrameTreeNode()
11095 0 : {
11096 0 : MOZ_COUNT_DTOR(DR_FrameTreeNode);
11097 0 : }
11098 :
11099 : nsIFrame* mFrame;
11100 : DR_FrameTreeNode* mParent;
11101 : bool mDisplay;
11102 : uint32_t mIndent;
11103 : };
11104 :
11105 : // DR_State implementation
11106 :
11107 3 : DR_State::DR_State()
11108 : : mInited(false), mActive(false), mCount(0), mAssert(-1), mIndent(0),
11109 3 : mIndentUndisplayedFrames(false), mDisplayPixelErrors(false)
11110 : {
11111 3 : MOZ_COUNT_CTOR(DR_State);
11112 3 : }
11113 :
11114 2 : void DR_State::Init()
11115 : {
11116 2 : char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT");
11117 : int32_t num;
11118 2 : if (env) {
11119 0 : if (GetNumber(env, num))
11120 0 : mAssert = num;
11121 : else
11122 0 : printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env);
11123 : }
11124 :
11125 2 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START");
11126 2 : if (env) {
11127 0 : if (GetNumber(env, num))
11128 0 : mIndent = num;
11129 : else
11130 0 : printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env);
11131 : }
11132 :
11133 2 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES");
11134 2 : if (env) {
11135 0 : if (GetNumber(env, num))
11136 0 : mIndentUndisplayedFrames = num;
11137 : else
11138 0 : printf("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s", env);
11139 : }
11140 :
11141 2 : env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS");
11142 2 : if (env) {
11143 0 : if (GetNumber(env, num))
11144 0 : mDisplayPixelErrors = num;
11145 : else
11146 0 : printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s", env);
11147 : }
11148 :
11149 2 : InitFrameTypeTable();
11150 2 : ParseRulesFile();
11151 2 : mInited = true;
11152 2 : }
11153 :
11154 0 : DR_State::~DR_State()
11155 : {
11156 0 : MOZ_COUNT_DTOR(DR_State);
11157 : int32_t numElements, i;
11158 0 : numElements = mWildRules.Length();
11159 0 : for (i = numElements - 1; i >= 0; i--) {
11160 0 : delete mWildRules.ElementAt(i);
11161 : }
11162 0 : numElements = mFrameTreeLeaves.Length();
11163 0 : for (i = numElements - 1; i >= 0; i--) {
11164 0 : delete mFrameTreeLeaves.ElementAt(i);
11165 : }
11166 0 : }
11167 :
11168 0 : bool DR_State::GetNumber(char* aBuf,
11169 : int32_t& aNumber)
11170 : {
11171 0 : if (sscanf(aBuf, "%d", &aNumber) > 0)
11172 0 : return true;
11173 : else
11174 0 : return false;
11175 : }
11176 :
11177 0 : bool DR_State::IsWhiteSpace(int c) {
11178 0 : return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
11179 : }
11180 :
11181 0 : bool DR_State::GetToken(FILE* aFile,
11182 : char* aBuf,
11183 : size_t aBufSize)
11184 : {
11185 0 : bool haveToken = false;
11186 0 : aBuf[0] = 0;
11187 : // get the 1st non whitespace char
11188 0 : int c = -1;
11189 0 : for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) {
11190 : }
11191 :
11192 0 : if (c > 0) {
11193 0 : haveToken = true;
11194 0 : aBuf[0] = c;
11195 : // get everything up to the next whitespace char
11196 : size_t cX;
11197 0 : for (cX = 1; cX + 1 < aBufSize ; cX++) {
11198 0 : c = getc(aFile);
11199 0 : if (c < 0) { // EOF
11200 0 : ungetc(' ', aFile);
11201 0 : break;
11202 : }
11203 : else {
11204 0 : if (IsWhiteSpace(c)) {
11205 0 : break;
11206 : }
11207 : else {
11208 0 : aBuf[cX] = c;
11209 : }
11210 : }
11211 : }
11212 0 : aBuf[cX] = 0;
11213 : }
11214 0 : return haveToken;
11215 : }
11216 :
11217 0 : DR_Rule* DR_State::ParseRule(FILE* aFile)
11218 : {
11219 : char buf[128];
11220 : int32_t doDisplay;
11221 0 : DR_Rule* rule = nullptr;
11222 0 : while (GetToken(aFile, buf, sizeof(buf))) {
11223 0 : if (GetNumber(buf, doDisplay)) {
11224 0 : if (rule) {
11225 0 : rule->mDisplay = !!doDisplay;
11226 0 : break;
11227 : }
11228 : else {
11229 0 : printf("unexpected token - %s \n", buf);
11230 : }
11231 : }
11232 : else {
11233 0 : if (!rule) {
11234 0 : rule = new DR_Rule;
11235 : }
11236 0 : if (strcmp(buf, "*") == 0) {
11237 0 : rule->AddPart(LayoutFrameType::None);
11238 : }
11239 : else {
11240 0 : DR_FrameTypeInfo* info = GetFrameTypeInfo(buf);
11241 0 : if (info) {
11242 0 : rule->AddPart(info->mType);
11243 : }
11244 : else {
11245 0 : printf("invalid frame type - %s \n", buf);
11246 : }
11247 : }
11248 : }
11249 : }
11250 0 : return rule;
11251 : }
11252 :
11253 0 : void DR_State::AddRule(nsTArray<DR_Rule*>& aRules,
11254 : DR_Rule& aRule)
11255 : {
11256 0 : int32_t numRules = aRules.Length();
11257 0 : for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
11258 0 : DR_Rule* rule = aRules.ElementAt(ruleX);
11259 0 : NS_ASSERTION(rule, "program error");
11260 0 : if (aRule.mLength > rule->mLength) {
11261 0 : aRules.InsertElementAt(ruleX, &aRule);
11262 0 : return;
11263 : }
11264 : }
11265 0 : aRules.AppendElement(&aRule);
11266 : }
11267 :
11268 2 : void DR_State::ParseRulesFile()
11269 : {
11270 2 : char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE");
11271 2 : if (path) {
11272 0 : FILE* inFile = fopen(path, "r");
11273 0 : if (inFile) {
11274 0 : for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
11275 0 : if (rule->mTarget) {
11276 0 : LayoutFrameType fType = rule->mTarget->mFrameType;
11277 0 : if (fType != LayoutFrameType::None) {
11278 0 : DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
11279 0 : AddRule(info->mRules, *rule);
11280 : }
11281 : else {
11282 0 : AddRule(mWildRules, *rule);
11283 : }
11284 0 : mActive = true;
11285 : }
11286 : }
11287 :
11288 0 : fclose(inFile);
11289 : }
11290 : }
11291 2 : }
11292 :
11293 : void
11294 70 : DR_State::AddFrameTypeInfo(LayoutFrameType aFrameType,
11295 : const char* aFrameNameAbbrev,
11296 : const char* aFrameName)
11297 : {
11298 70 : mFrameTypeTable.AppendElement(DR_FrameTypeInfo(aFrameType, aFrameNameAbbrev, aFrameName));
11299 70 : }
11300 :
11301 : DR_FrameTypeInfo*
11302 0 : DR_State::GetFrameTypeInfo(LayoutFrameType aFrameType)
11303 : {
11304 0 : int32_t numEntries = mFrameTypeTable.Length();
11305 0 : NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
11306 0 : for (int32_t i = 0; i < numEntries; i++) {
11307 0 : DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
11308 0 : if (info.mType == aFrameType) {
11309 0 : return &info;
11310 : }
11311 : }
11312 0 : return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
11313 : }
11314 :
11315 0 : DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName)
11316 : {
11317 0 : int32_t numEntries = mFrameTypeTable.Length();
11318 0 : NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
11319 0 : for (int32_t i = 0; i < numEntries; i++) {
11320 0 : DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
11321 0 : if ((strcmp(aFrameName, info.mName) == 0) || (strcmp(aFrameName, info.mNameAbbrev) == 0)) {
11322 0 : return &info;
11323 : }
11324 : }
11325 0 : return &mFrameTypeTable.ElementAt(numEntries - 1); // return unknown frame type
11326 : }
11327 :
11328 2 : void DR_State::InitFrameTypeTable()
11329 : {
11330 2 : AddFrameTypeInfo(LayoutFrameType::Block, "block", "block");
11331 2 : AddFrameTypeInfo(LayoutFrameType::Br, "br", "br");
11332 2 : AddFrameTypeInfo(LayoutFrameType::Bullet, "bullet", "bullet");
11333 2 : AddFrameTypeInfo(LayoutFrameType::ColorControl, "color", "colorControl");
11334 2 : AddFrameTypeInfo(LayoutFrameType::GfxButtonControl, "button", "gfxButtonControl");
11335 2 : AddFrameTypeInfo(LayoutFrameType::HTMLButtonControl, "HTMLbutton", "HTMLButtonControl");
11336 2 : AddFrameTypeInfo(LayoutFrameType::HTMLCanvas, "HTMLCanvas","HTMLCanvas");
11337 2 : AddFrameTypeInfo(LayoutFrameType::SubDocument, "subdoc", "subDocument");
11338 2 : AddFrameTypeInfo(LayoutFrameType::Image, "img", "image");
11339 2 : AddFrameTypeInfo(LayoutFrameType::Inline, "inline", "inline");
11340 2 : AddFrameTypeInfo(LayoutFrameType::Letter, "letter", "letter");
11341 2 : AddFrameTypeInfo(LayoutFrameType::Line, "line", "line");
11342 2 : AddFrameTypeInfo(LayoutFrameType::ListControl, "select", "select");
11343 2 : AddFrameTypeInfo(LayoutFrameType::Object, "obj", "object");
11344 2 : AddFrameTypeInfo(LayoutFrameType::Page, "page", "page");
11345 2 : AddFrameTypeInfo(LayoutFrameType::Placeholder, "place", "placeholder");
11346 2 : AddFrameTypeInfo(LayoutFrameType::Canvas, "canvas", "canvas");
11347 2 : AddFrameTypeInfo(LayoutFrameType::Root, "root", "root");
11348 2 : AddFrameTypeInfo(LayoutFrameType::Scroll, "scroll", "scroll");
11349 2 : AddFrameTypeInfo(LayoutFrameType::TableCell, "cell", "tableCell");
11350 2 : AddFrameTypeInfo(LayoutFrameType::BCTableCell, "bcCell", "bcTableCell");
11351 2 : AddFrameTypeInfo(LayoutFrameType::TableCol, "col", "tableCol");
11352 2 : AddFrameTypeInfo(LayoutFrameType::TableColGroup, "colG", "tableColGroup");
11353 2 : AddFrameTypeInfo(LayoutFrameType::Table, "tbl", "table");
11354 2 : AddFrameTypeInfo(LayoutFrameType::TableWrapper, "tblW", "tableWrapper");
11355 2 : AddFrameTypeInfo(LayoutFrameType::TableRowGroup, "rowG", "tableRowGroup");
11356 2 : AddFrameTypeInfo(LayoutFrameType::TableRow, "row", "tableRow");
11357 2 : AddFrameTypeInfo(LayoutFrameType::TextInput, "textCtl", "textInput");
11358 2 : AddFrameTypeInfo(LayoutFrameType::Text, "text", "text");
11359 2 : AddFrameTypeInfo(LayoutFrameType::Viewport, "VP", "viewport");
11360 : #ifdef MOZ_XUL
11361 2 : AddFrameTypeInfo(LayoutFrameType::XULLabel, "XULLabel", "XULLabel");
11362 2 : AddFrameTypeInfo(LayoutFrameType::Box, "Box", "Box");
11363 2 : AddFrameTypeInfo(LayoutFrameType::Slider, "Slider", "Slider");
11364 2 : AddFrameTypeInfo(LayoutFrameType::PopupSet, "PopupSet", "PopupSet");
11365 : #endif
11366 2 : AddFrameTypeInfo(LayoutFrameType::None, "unknown", "unknown");
11367 2 : }
11368 :
11369 :
11370 0 : void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame,
11371 : int32_t aIndent)
11372 : {
11373 0 : DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->Type());
11374 0 : if (frameTypeInfo) {
11375 0 : for (int32_t i = 0; i < aIndent; i++) {
11376 0 : printf(" ");
11377 : }
11378 0 : if(!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) {
11379 0 : if (aFrame) {
11380 0 : nsAutoString name;
11381 0 : aFrame->GetFrameName(name);
11382 0 : printf("%s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)aFrame);
11383 : }
11384 : else {
11385 0 : printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
11386 : }
11387 : }
11388 : else {
11389 0 : printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
11390 : }
11391 : }
11392 0 : }
11393 :
11394 : bool
11395 0 : DR_State::RuleMatches(DR_Rule& aRule, DR_FrameTreeNode& aNode)
11396 : {
11397 0 : NS_ASSERTION(aRule.mTarget, "program error");
11398 :
11399 : DR_RulePart* rulePart;
11400 : DR_FrameTreeNode* parentNode;
11401 0 : for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent;
11402 0 : rulePart && parentNode;
11403 0 : rulePart = rulePart->mNext, parentNode = parentNode->mParent) {
11404 0 : if (rulePart->mFrameType != LayoutFrameType::None) {
11405 0 : if (parentNode->mFrame) {
11406 0 : if (rulePart->mFrameType != parentNode->mFrame->Type()) {
11407 0 : return false;
11408 : }
11409 0 : } else NS_ASSERTION(false, "program error");
11410 : }
11411 : // else wild card match
11412 : }
11413 0 : return true;
11414 : }
11415 :
11416 0 : void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode)
11417 : {
11418 0 : if (!aNode.mFrame) {
11419 0 : NS_ASSERTION(false, "invalid DR_FrameTreeNode \n");
11420 0 : return;
11421 : }
11422 :
11423 0 : bool matchingRule = false;
11424 :
11425 0 : DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->Type());
11426 0 : NS_ASSERTION(info, "program error");
11427 0 : int32_t numRules = info->mRules.Length();
11428 0 : for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
11429 0 : DR_Rule* rule = info->mRules.ElementAt(ruleX);
11430 0 : if (rule && RuleMatches(*rule, aNode)) {
11431 0 : aNode.mDisplay = rule->mDisplay;
11432 0 : matchingRule = true;
11433 0 : break;
11434 : }
11435 : }
11436 0 : if (!matchingRule) {
11437 0 : int32_t numWildRules = mWildRules.Length();
11438 0 : for (int32_t ruleX = 0; ruleX < numWildRules; ruleX++) {
11439 0 : DR_Rule* rule = mWildRules.ElementAt(ruleX);
11440 0 : if (rule && RuleMatches(*rule, aNode)) {
11441 0 : aNode.mDisplay = rule->mDisplay;
11442 0 : break;
11443 : }
11444 : }
11445 : }
11446 : }
11447 :
11448 0 : DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame* aFrame,
11449 : const ReflowInput* aReflowInput)
11450 : {
11451 : // find the frame of the parent reflow state (usually just the parent of aFrame)
11452 : nsIFrame* parentFrame;
11453 0 : if (aReflowInput) {
11454 0 : const ReflowInput* parentRI = aReflowInput->mParentReflowInput;
11455 0 : parentFrame = (parentRI) ? parentRI->mFrame : nullptr;
11456 : } else {
11457 0 : parentFrame = aFrame->GetParent();
11458 : }
11459 :
11460 : // find the parent tree node leaf
11461 0 : DR_FrameTreeNode* parentNode = nullptr;
11462 :
11463 0 : DR_FrameTreeNode* lastLeaf = nullptr;
11464 0 : if(mFrameTreeLeaves.Length())
11465 0 : lastLeaf = mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Length() - 1);
11466 0 : if (lastLeaf) {
11467 0 : for (parentNode = lastLeaf; parentNode && (parentNode->mFrame != parentFrame); parentNode = parentNode->mParent) {
11468 : }
11469 : }
11470 0 : DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode);
11471 0 : FindMatchingRule(*newNode);
11472 :
11473 0 : newNode->mIndent = mIndent;
11474 0 : if (newNode->mDisplay || mIndentUndisplayedFrames) {
11475 0 : ++mIndent;
11476 : }
11477 :
11478 0 : if (lastLeaf && (lastLeaf == parentNode)) {
11479 0 : mFrameTreeLeaves.RemoveElementAt(mFrameTreeLeaves.Length() - 1);
11480 : }
11481 0 : mFrameTreeLeaves.AppendElement(newNode);
11482 0 : mCount++;
11483 :
11484 0 : return newNode;
11485 : }
11486 :
11487 0 : void DR_State::PrettyUC(nscoord aSize,
11488 : char* aBuf,
11489 : int aBufSize)
11490 : {
11491 0 : if (NS_UNCONSTRAINEDSIZE == aSize) {
11492 0 : strcpy(aBuf, "UC");
11493 : }
11494 : else {
11495 0 : if ((nscoord)0xdeadbeefU == aSize)
11496 : {
11497 0 : strcpy(aBuf, "deadbeef");
11498 : }
11499 : else {
11500 0 : snprintf(aBuf, aBufSize, "%d", aSize);
11501 : }
11502 : }
11503 0 : }
11504 :
11505 0 : void DR_State::PrintMargin(const char *tag, const nsMargin* aMargin)
11506 : {
11507 0 : if (aMargin) {
11508 : char t[16], r[16], b[16], l[16];
11509 0 : PrettyUC(aMargin->top, t, 16);
11510 0 : PrettyUC(aMargin->right, r, 16);
11511 0 : PrettyUC(aMargin->bottom, b, 16);
11512 0 : PrettyUC(aMargin->left, l, 16);
11513 0 : printf(" %s=%s,%s,%s,%s", tag, t, r, b, l);
11514 : } else {
11515 : // use %p here for consistency with other null-pointer printouts
11516 0 : printf(" %s=%p", tag, (void*)aMargin);
11517 : }
11518 0 : }
11519 :
11520 0 : void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode)
11521 : {
11522 0 : mFrameTreeLeaves.RemoveElement(&aNode);
11523 0 : int32_t numLeaves = mFrameTreeLeaves.Length();
11524 0 : if ((0 == numLeaves) || (aNode.mParent != mFrameTreeLeaves.ElementAt(numLeaves - 1))) {
11525 0 : mFrameTreeLeaves.AppendElement(aNode.mParent);
11526 : }
11527 :
11528 0 : if (aNode.mDisplay || mIndentUndisplayedFrames) {
11529 0 : --mIndent;
11530 : }
11531 : // delete the tree node
11532 0 : delete &aNode;
11533 0 : }
11534 :
11535 : static void
11536 0 : CheckPixelError(nscoord aSize,
11537 : int32_t aPixelToTwips)
11538 : {
11539 0 : if (NS_UNCONSTRAINEDSIZE != aSize) {
11540 0 : if ((aSize % aPixelToTwips) > 0) {
11541 0 : printf("VALUE %d is not a whole pixel \n", aSize);
11542 : }
11543 : }
11544 0 : }
11545 :
11546 0 : static void DisplayReflowEnterPrint(nsPresContext* aPresContext,
11547 : nsIFrame* aFrame,
11548 : const ReflowInput& aReflowInput,
11549 : DR_FrameTreeNode& aTreeNode,
11550 : bool aChanged)
11551 : {
11552 0 : if (aTreeNode.mDisplay) {
11553 0 : DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent);
11554 :
11555 : char width[16];
11556 : char height[16];
11557 :
11558 0 : DR_state->PrettyUC(aReflowInput.AvailableWidth(), width, 16);
11559 0 : DR_state->PrettyUC(aReflowInput.AvailableHeight(), height, 16);
11560 0 : printf("Reflow a=%s,%s ", width, height);
11561 :
11562 0 : DR_state->PrettyUC(aReflowInput.ComputedWidth(), width, 16);
11563 0 : DR_state->PrettyUC(aReflowInput.ComputedHeight(), height, 16);
11564 0 : printf("c=%s,%s ", width, height);
11565 :
11566 0 : if (aFrame->GetStateBits() & NS_FRAME_IS_DIRTY)
11567 0 : printf("dirty ");
11568 :
11569 0 : if (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)
11570 0 : printf("dirty-children ");
11571 :
11572 0 : if (aReflowInput.mFlags.mSpecialBSizeReflow)
11573 0 : printf("special-bsize ");
11574 :
11575 0 : if (aReflowInput.IsHResize())
11576 0 : printf("h-resize ");
11577 :
11578 0 : if (aReflowInput.IsVResize())
11579 0 : printf("v-resize ");
11580 :
11581 0 : nsIFrame* inFlow = aFrame->GetPrevInFlow();
11582 0 : if (inFlow) {
11583 0 : printf("pif=%p ", (void*)inFlow);
11584 : }
11585 0 : inFlow = aFrame->GetNextInFlow();
11586 0 : if (inFlow) {
11587 0 : printf("nif=%p ", (void*)inFlow);
11588 : }
11589 0 : if (aChanged)
11590 0 : printf("CHANGED \n");
11591 : else
11592 0 : printf("cnt=%d \n", DR_state->mCount);
11593 0 : if (DR_state->mDisplayPixelErrors) {
11594 0 : int32_t p2t = aPresContext->AppUnitsPerDevPixel();
11595 0 : CheckPixelError(aReflowInput.AvailableWidth(), p2t);
11596 0 : CheckPixelError(aReflowInput.AvailableHeight(), p2t);
11597 0 : CheckPixelError(aReflowInput.ComputedWidth(), p2t);
11598 0 : CheckPixelError(aReflowInput.ComputedHeight(), p2t);
11599 : }
11600 : }
11601 0 : }
11602 :
11603 587 : void* nsFrame::DisplayReflowEnter(nsPresContext* aPresContext,
11604 : nsIFrame* aFrame,
11605 : const ReflowInput& aReflowInput)
11606 : {
11607 587 : if (!DR_state->mInited) DR_state->Init();
11608 587 : if (!DR_state->mActive) return nullptr;
11609 :
11610 0 : NS_ASSERTION(aFrame, "invalid call");
11611 :
11612 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowInput);
11613 0 : if (treeNode) {
11614 0 : DisplayReflowEnterPrint(aPresContext, aFrame, aReflowInput, *treeNode, false);
11615 : }
11616 0 : return treeNode;
11617 : }
11618 :
11619 884 : void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame)
11620 : {
11621 884 : if (!DR_state->mInited) DR_state->Init();
11622 884 : if (!DR_state->mActive) return nullptr;
11623 :
11624 0 : NS_ASSERTION(aFrame, "invalid call");
11625 :
11626 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
11627 0 : if (treeNode && treeNode->mDisplay) {
11628 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11629 0 : printf("XULLayout\n");
11630 : }
11631 0 : return treeNode;
11632 : }
11633 :
11634 608 : void* nsFrame::DisplayIntrinsicISizeEnter(nsIFrame* aFrame,
11635 : const char* aType)
11636 : {
11637 608 : if (!DR_state->mInited) DR_state->Init();
11638 608 : if (!DR_state->mActive) return nullptr;
11639 :
11640 0 : NS_ASSERTION(aFrame, "invalid call");
11641 :
11642 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
11643 0 : if (treeNode && treeNode->mDisplay) {
11644 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11645 0 : printf("Get%sWidth\n", aType);
11646 : }
11647 0 : return treeNode;
11648 : }
11649 :
11650 10263 : void* nsFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame,
11651 : const char* aType)
11652 : {
11653 10263 : if (!DR_state->mInited) DR_state->Init();
11654 10263 : if (!DR_state->mActive) return nullptr;
11655 :
11656 0 : NS_ASSERTION(aFrame, "invalid call");
11657 :
11658 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
11659 0 : if (treeNode && treeNode->mDisplay) {
11660 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11661 0 : printf("Get%sSize\n", aType);
11662 : }
11663 0 : return treeNode;
11664 : }
11665 :
11666 587 : void nsFrame::DisplayReflowExit(nsPresContext* aPresContext,
11667 : nsIFrame* aFrame,
11668 : ReflowOutput& aMetrics,
11669 : const nsReflowStatus& aStatus,
11670 : void* aFrameTreeNode)
11671 : {
11672 587 : if (!DR_state->mActive) return;
11673 :
11674 0 : NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call");
11675 0 : if (!aFrameTreeNode) return;
11676 :
11677 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
11678 0 : if (treeNode->mDisplay) {
11679 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11680 :
11681 : char width[16];
11682 : char height[16];
11683 : char x[16];
11684 : char y[16];
11685 0 : DR_state->PrettyUC(aMetrics.Width(), width, 16);
11686 0 : DR_state->PrettyUC(aMetrics.Height(), height, 16);
11687 0 : printf("Reflow d=%s,%s", width, height);
11688 :
11689 0 : if (!aStatus.IsEmpty()) {
11690 0 : printf(" status=%s", ToString(aStatus).c_str());
11691 : }
11692 0 : if (aFrame->HasOverflowAreas()) {
11693 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().x, x, 16);
11694 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().y, y, 16);
11695 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().width, width, 16);
11696 0 : DR_state->PrettyUC(aMetrics.VisualOverflow().height, height, 16);
11697 0 : printf(" vis-o=(%s,%s) %s x %s", x, y, width, height);
11698 :
11699 0 : nsRect storedOverflow = aFrame->GetVisualOverflowRect();
11700 0 : DR_state->PrettyUC(storedOverflow.x, x, 16);
11701 0 : DR_state->PrettyUC(storedOverflow.y, y, 16);
11702 0 : DR_state->PrettyUC(storedOverflow.width, width, 16);
11703 0 : DR_state->PrettyUC(storedOverflow.height, height, 16);
11704 0 : printf(" vis-sto=(%s,%s) %s x %s", x, y, width, height);
11705 :
11706 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().x, x, 16);
11707 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().y, y, 16);
11708 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().width, width, 16);
11709 0 : DR_state->PrettyUC(aMetrics.ScrollableOverflow().height, height, 16);
11710 0 : printf(" scr-o=(%s,%s) %s x %s", x, y, width, height);
11711 :
11712 0 : storedOverflow = aFrame->GetScrollableOverflowRect();
11713 0 : DR_state->PrettyUC(storedOverflow.x, x, 16);
11714 0 : DR_state->PrettyUC(storedOverflow.y, y, 16);
11715 0 : DR_state->PrettyUC(storedOverflow.width, width, 16);
11716 0 : DR_state->PrettyUC(storedOverflow.height, height, 16);
11717 0 : printf(" scr-sto=(%s,%s) %s x %s", x, y, width, height);
11718 : }
11719 0 : printf("\n");
11720 0 : if (DR_state->mDisplayPixelErrors) {
11721 0 : int32_t p2t = aPresContext->AppUnitsPerDevPixel();
11722 0 : CheckPixelError(aMetrics.Width(), p2t);
11723 0 : CheckPixelError(aMetrics.Height(), p2t);
11724 : }
11725 : }
11726 0 : DR_state->DeleteTreeNode(*treeNode);
11727 : }
11728 :
11729 884 : void nsFrame::DisplayLayoutExit(nsIFrame* aFrame,
11730 : void* aFrameTreeNode)
11731 : {
11732 884 : if (!DR_state->mActive) return;
11733 :
11734 0 : NS_ASSERTION(aFrame, "non-null frame required");
11735 0 : if (!aFrameTreeNode) return;
11736 :
11737 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
11738 0 : if (treeNode->mDisplay) {
11739 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11740 0 : nsRect rect = aFrame->GetRect();
11741 0 : printf("XULLayout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
11742 : }
11743 0 : DR_state->DeleteTreeNode(*treeNode);
11744 : }
11745 :
11746 608 : void nsFrame::DisplayIntrinsicISizeExit(nsIFrame* aFrame,
11747 : const char* aType,
11748 : nscoord aResult,
11749 : void* aFrameTreeNode)
11750 : {
11751 608 : if (!DR_state->mActive) return;
11752 :
11753 0 : NS_ASSERTION(aFrame, "non-null frame required");
11754 0 : if (!aFrameTreeNode) return;
11755 :
11756 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
11757 0 : if (treeNode->mDisplay) {
11758 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11759 : char width[16];
11760 0 : DR_state->PrettyUC(aResult, width, 16);
11761 0 : printf("Get%sWidth=%s\n", aType, width);
11762 : }
11763 0 : DR_state->DeleteTreeNode(*treeNode);
11764 : }
11765 :
11766 10263 : void nsFrame::DisplayIntrinsicSizeExit(nsIFrame* aFrame,
11767 : const char* aType,
11768 : nsSize aResult,
11769 : void* aFrameTreeNode)
11770 : {
11771 10263 : if (!DR_state->mActive) return;
11772 :
11773 0 : NS_ASSERTION(aFrame, "non-null frame required");
11774 0 : if (!aFrameTreeNode) return;
11775 :
11776 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
11777 0 : if (treeNode->mDisplay) {
11778 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11779 :
11780 : char width[16];
11781 : char height[16];
11782 0 : DR_state->PrettyUC(aResult.width, width, 16);
11783 0 : DR_state->PrettyUC(aResult.height, height, 16);
11784 0 : printf("Get%sSize=%s,%s\n", aType, width, height);
11785 : }
11786 0 : DR_state->DeleteTreeNode(*treeNode);
11787 : }
11788 :
11789 : /* static */ void
11790 3 : nsFrame::DisplayReflowStartup()
11791 : {
11792 3 : DR_state = new DR_State();
11793 3 : }
11794 :
11795 : /* static */ void
11796 0 : nsFrame::DisplayReflowShutdown()
11797 : {
11798 0 : delete DR_state;
11799 0 : DR_state = nullptr;
11800 0 : }
11801 :
11802 0 : void DR_cookie::Change() const
11803 : {
11804 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue;
11805 0 : if (treeNode && treeNode->mDisplay) {
11806 0 : DisplayReflowEnterPrint(mPresContext, mFrame, mReflowInput, *treeNode, true);
11807 : }
11808 0 : }
11809 :
11810 : /* static */ void*
11811 652 : ReflowInput::DisplayInitConstraintsEnter(nsIFrame* aFrame,
11812 : ReflowInput* aState,
11813 : nscoord aContainingBlockWidth,
11814 : nscoord aContainingBlockHeight,
11815 : const nsMargin* aBorder,
11816 : const nsMargin* aPadding)
11817 : {
11818 652 : NS_PRECONDITION(aFrame, "non-null frame required");
11819 652 : NS_PRECONDITION(aState, "non-null state required");
11820 :
11821 652 : if (!DR_state->mInited) DR_state->Init();
11822 652 : if (!DR_state->mActive) return nullptr;
11823 :
11824 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aState);
11825 0 : if (treeNode && treeNode->mDisplay) {
11826 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11827 :
11828 : printf("InitConstraints parent=%p",
11829 0 : (void*)aState->mParentReflowInput);
11830 :
11831 : char width[16];
11832 : char height[16];
11833 :
11834 0 : DR_state->PrettyUC(aContainingBlockWidth, width, 16);
11835 0 : DR_state->PrettyUC(aContainingBlockHeight, height, 16);
11836 0 : printf(" cb=%s,%s", width, height);
11837 :
11838 0 : DR_state->PrettyUC(aState->AvailableWidth(), width, 16);
11839 0 : DR_state->PrettyUC(aState->AvailableHeight(), height, 16);
11840 0 : printf(" as=%s,%s", width, height);
11841 :
11842 0 : DR_state->PrintMargin("b", aBorder);
11843 0 : DR_state->PrintMargin("p", aPadding);
11844 0 : putchar('\n');
11845 : }
11846 0 : return treeNode;
11847 : }
11848 :
11849 : /* static */ void
11850 652 : ReflowInput::DisplayInitConstraintsExit(nsIFrame* aFrame,
11851 : ReflowInput* aState,
11852 : void* aValue)
11853 : {
11854 652 : NS_PRECONDITION(aFrame, "non-null frame required");
11855 652 : NS_PRECONDITION(aState, "non-null state required");
11856 :
11857 652 : if (!DR_state->mActive) return;
11858 0 : if (!aValue) return;
11859 :
11860 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
11861 0 : if (treeNode->mDisplay) {
11862 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11863 : char cmiw[16], cw[16], cmxw[16], cmih[16], ch[16], cmxh[16];
11864 0 : DR_state->PrettyUC(aState->ComputedMinWidth(), cmiw, 16);
11865 0 : DR_state->PrettyUC(aState->ComputedWidth(), cw, 16);
11866 0 : DR_state->PrettyUC(aState->ComputedMaxWidth(), cmxw, 16);
11867 0 : DR_state->PrettyUC(aState->ComputedMinHeight(), cmih, 16);
11868 0 : DR_state->PrettyUC(aState->ComputedHeight(), ch, 16);
11869 0 : DR_state->PrettyUC(aState->ComputedMaxHeight(), cmxh, 16);
11870 : printf("InitConstraints= cw=(%s <= %s <= %s) ch=(%s <= %s <= %s)",
11871 0 : cmiw, cw, cmxw, cmih, ch, cmxh);
11872 0 : DR_state->PrintMargin("co", &aState->ComputedPhysicalOffsets());
11873 0 : putchar('\n');
11874 : }
11875 0 : DR_state->DeleteTreeNode(*treeNode);
11876 : }
11877 :
11878 :
11879 : /* static */ void*
11880 652 : SizeComputationInput::DisplayInitOffsetsEnter(nsIFrame* aFrame,
11881 : SizeComputationInput* aState,
11882 : const LogicalSize& aPercentBasis,
11883 : WritingMode aCBWritingMode,
11884 : const nsMargin* aBorder,
11885 : const nsMargin* aPadding)
11886 : {
11887 652 : NS_PRECONDITION(aFrame, "non-null frame required");
11888 652 : NS_PRECONDITION(aState, "non-null state required");
11889 :
11890 652 : if (!DR_state->mInited) DR_state->Init();
11891 652 : if (!DR_state->mActive) return nullptr;
11892 :
11893 : // aState is not necessarily a ReflowInput
11894 0 : DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
11895 0 : if (treeNode && treeNode->mDisplay) {
11896 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11897 :
11898 : char horizPctBasisStr[16];
11899 : char vertPctBasisStr[16];
11900 0 : DR_state->PrettyUC(aPercentBasis.ISize(aCBWritingMode),
11901 0 : horizPctBasisStr, 16);
11902 0 : DR_state->PrettyUC(aPercentBasis.BSize(aCBWritingMode),
11903 0 : vertPctBasisStr, 16);
11904 0 : printf("InitOffsets pct_basis=%s,%s", horizPctBasisStr, vertPctBasisStr);
11905 :
11906 0 : DR_state->PrintMargin("b", aBorder);
11907 0 : DR_state->PrintMargin("p", aPadding);
11908 0 : putchar('\n');
11909 : }
11910 0 : return treeNode;
11911 : }
11912 :
11913 : /* static */ void
11914 652 : SizeComputationInput::DisplayInitOffsetsExit(nsIFrame* aFrame,
11915 : SizeComputationInput* aState,
11916 : void* aValue)
11917 : {
11918 652 : NS_PRECONDITION(aFrame, "non-null frame required");
11919 652 : NS_PRECONDITION(aState, "non-null state required");
11920 :
11921 652 : if (!DR_state->mActive) return;
11922 0 : if (!aValue) return;
11923 :
11924 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
11925 0 : if (treeNode->mDisplay) {
11926 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11927 0 : printf("InitOffsets=");
11928 0 : DR_state->PrintMargin("m", &aState->ComputedPhysicalMargin());
11929 0 : DR_state->PrintMargin("p", &aState->ComputedPhysicalPadding());
11930 0 : DR_state->PrintMargin("p+b", &aState->ComputedPhysicalBorderPadding());
11931 0 : putchar('\n');
11932 : }
11933 0 : DR_state->DeleteTreeNode(*treeNode);
11934 : }
11935 :
11936 : /* static */ void*
11937 652 : ReflowInput::DisplayInitFrameTypeEnter(nsIFrame* aFrame,
11938 : ReflowInput* aState)
11939 : {
11940 652 : NS_PRECONDITION(aFrame, "non-null frame required");
11941 652 : NS_PRECONDITION(aState, "non-null state required");
11942 :
11943 652 : if (!DR_state->mInited) DR_state->Init();
11944 652 : if (!DR_state->mActive) return nullptr;
11945 :
11946 : // we don't print anything here
11947 0 : return DR_state->CreateTreeNode(aFrame, aState);
11948 : }
11949 :
11950 : /* static */ void
11951 652 : ReflowInput::DisplayInitFrameTypeExit(nsIFrame* aFrame,
11952 : ReflowInput* aState,
11953 : void* aValue)
11954 : {
11955 652 : NS_PRECONDITION(aFrame, "non-null frame required");
11956 652 : NS_PRECONDITION(aState, "non-null state required");
11957 :
11958 652 : if (!DR_state->mActive) return;
11959 0 : if (!aValue) return;
11960 :
11961 0 : DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
11962 0 : if (treeNode->mDisplay) {
11963 0 : DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
11964 0 : printf("InitFrameType");
11965 :
11966 0 : const nsStyleDisplay *disp = aState->mStyleDisplay;
11967 :
11968 0 : if (aFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
11969 0 : printf(" out-of-flow");
11970 0 : if (aFrame->GetPrevInFlow())
11971 0 : printf(" prev-in-flow");
11972 0 : if (aFrame->IsAbsolutelyPositioned())
11973 0 : printf(" abspos");
11974 0 : if (aFrame->IsFloating())
11975 0 : printf(" float");
11976 :
11977 : // This array must exactly match the StyleDisplay enum.
11978 : const char *const displayTypes[] = {
11979 : "none", "block", "inline", "inline-block", "list-item", "table",
11980 : "inline-table", "table-row-group", "table-column", "table-column",
11981 : "table-column-group", "table-header-group", "table-footer-group",
11982 : "table-row", "table-cell", "table-caption", "flex", "inline-flex",
11983 : "grid", "inline-grid", "ruby", "ruby-base", "ruby-base-container",
11984 : "ruby-text", "ruby-text-container", "contents", "-webkit-box",
11985 : "-webkit-inline-box", "box", "inline-box",
11986 : #ifdef MOZ_XUL
11987 : "grid", "inline-grid", "grid-group", "grid-line", "stack",
11988 : "inline-stack", "deck", "groupbox", "popup",
11989 : #endif
11990 0 : };
11991 0 : const uint32_t display = static_cast<uint32_t>(disp->mDisplay);
11992 0 : if (display >= ArrayLength(displayTypes))
11993 0 : printf(" display=%u", display);
11994 : else
11995 0 : printf(" display=%s", displayTypes[display]);
11996 :
11997 : // This array must exactly match the NS_CSS_FRAME_TYPE constants.
11998 : const char *const cssFrameTypes[] = {
11999 : "unknown", "inline", "block", "floating", "absolute", "internal-table"
12000 0 : };
12001 0 : nsCSSFrameType bareType = NS_FRAME_GET_TYPE(aState->mFrameType);
12002 0 : bool repNoBlock = NS_FRAME_IS_REPLACED_NOBLOCK(aState->mFrameType);
12003 0 : bool repBlock = NS_FRAME_IS_REPLACED_CONTAINS_BLOCK(aState->mFrameType);
12004 :
12005 0 : if (bareType >= ArrayLength(cssFrameTypes)) {
12006 0 : printf(" result=type %u", bareType);
12007 : } else {
12008 0 : printf(" result=%s", cssFrameTypes[bareType]);
12009 : }
12010 0 : printf("%s%s\n", repNoBlock ? " +rep" : "", repBlock ? " +repBlk" : "");
12011 : }
12012 0 : DR_state->DeleteTreeNode(*treeNode);
12013 : }
12014 :
12015 : #endif
12016 : // End Display Reflow
12017 :
12018 : #endif
|