Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / layout / generic / nsRubyTextContainerFrame.cpp
blob8494b36a2819a865452ad458fcd74930d18eb950
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* rendering object for CSS "display: ruby-text-container" */
9 #include "nsRubyTextContainerFrame.h"
11 #include "mozilla/ComputedStyle.h"
12 #include "mozilla/PresShell.h"
13 #include "mozilla/UniquePtr.h"
14 #include "mozilla/WritingModes.h"
15 #include "nsLayoutUtils.h"
16 #include "nsLineLayout.h"
17 #include "nsPresContext.h"
19 using namespace mozilla;
21 //----------------------------------------------------------------------
23 // Frame class boilerplate
24 // =======================
26 NS_QUERYFRAME_HEAD(nsRubyTextContainerFrame)
27 NS_QUERYFRAME_ENTRY(nsRubyTextContainerFrame)
28 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
30 NS_IMPL_FRAMEARENA_HELPERS(nsRubyTextContainerFrame)
32 nsContainerFrame* NS_NewRubyTextContainerFrame(PresShell* aPresShell,
33 ComputedStyle* aStyle) {
34 return new (aPresShell)
35 nsRubyTextContainerFrame(aStyle, aPresShell->GetPresContext());
38 //----------------------------------------------------------------------
40 // nsRubyTextContainerFrame Method Implementations
41 // ===============================================
43 #ifdef DEBUG_FRAME_DUMP
44 nsresult nsRubyTextContainerFrame::GetFrameName(nsAString& aResult) const {
45 return MakeFrameName(u"RubyTextContainer"_ns, aResult);
47 #endif
49 /* virtual */
50 void nsRubyTextContainerFrame::SetInitialChildList(ChildListID aListID,
51 nsFrameList&& aChildList) {
52 nsContainerFrame::SetInitialChildList(aListID, std::move(aChildList));
53 if (aListID == FrameChildListID::Principal) {
54 UpdateSpanFlag();
58 /* virtual */
59 void nsRubyTextContainerFrame::AppendFrames(ChildListID aListID,
60 nsFrameList&& aFrameList) {
61 nsContainerFrame::AppendFrames(aListID, std::move(aFrameList));
62 UpdateSpanFlag();
65 /* virtual */
66 void nsRubyTextContainerFrame::InsertFrames(
67 ChildListID aListID, nsIFrame* aPrevFrame,
68 const nsLineList::iterator* aPrevFrameLine, nsFrameList&& aFrameList) {
69 nsContainerFrame::InsertFrames(aListID, aPrevFrame, aPrevFrameLine,
70 std::move(aFrameList));
71 UpdateSpanFlag();
74 /* virtual */
75 void nsRubyTextContainerFrame::RemoveFrame(DestroyContext& aContext,
76 ChildListID aListID,
77 nsIFrame* aOldFrame) {
78 nsContainerFrame::RemoveFrame(aContext, aListID, aOldFrame);
79 UpdateSpanFlag();
82 void nsRubyTextContainerFrame::UpdateSpanFlag() {
83 bool isSpan = false;
84 // The continuation checks are safe here because spans never break.
85 if (!GetPrevContinuation() && !GetNextContinuation()) {
86 nsIFrame* onlyChild = mFrames.OnlyChild();
87 if (onlyChild && onlyChild->IsPseudoFrame(GetContent())) {
88 // Per CSS Ruby spec, if the only child of an rtc frame is
89 // a pseudo rt frame, it spans all bases in the segment.
90 isSpan = true;
94 if (isSpan) {
95 AddStateBits(NS_RUBY_TEXT_CONTAINER_IS_SPAN);
96 } else {
97 RemoveStateBits(NS_RUBY_TEXT_CONTAINER_IS_SPAN);
101 /* virtual */
102 void nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
103 ReflowOutput& aDesiredSize,
104 const ReflowInput& aReflowInput,
105 nsReflowStatus& aStatus) {
106 MarkInReflow();
107 DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame");
108 MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
110 // Although a ruby text container may have continuations, returning
111 // complete reflow status is still safe, since its parent, ruby frame,
112 // ignores the status, and continuations of the ruby base container
113 // will take care of our continuations.
114 WritingMode rtcWM = GetWritingMode();
116 nscoord minBCoord = nscoord_MAX;
117 nscoord maxBCoord = nscoord_MIN;
118 // The container size is not yet known, so we use a dummy (0, 0) size.
119 // The block-dir position will be corrected below after containerSize
120 // is finalized.
121 const nsSize dummyContainerSize;
122 for (nsIFrame* child : mFrames) {
123 MOZ_ASSERT(child->IsRubyTextFrame());
124 LogicalRect rect = child->GetLogicalRect(rtcWM, dummyContainerSize);
125 LogicalMargin margin = child->GetLogicalUsedMargin(rtcWM);
126 nscoord blockStart = rect.BStart(rtcWM) - margin.BStart(rtcWM);
127 minBCoord = std::min(minBCoord, blockStart);
128 nscoord blockEnd = rect.BEnd(rtcWM) + margin.BEnd(rtcWM);
129 maxBCoord = std::max(maxBCoord, blockEnd);
132 if (!mFrames.IsEmpty()) {
133 if (MOZ_UNLIKELY(minBCoord > maxBCoord)) {
134 // XXX When bug 765861 gets fixed, this warning should be upgraded.
135 NS_WARNING("bad block coord");
136 minBCoord = maxBCoord = 0;
138 LogicalSize size(rtcWM, mISize, maxBCoord - minBCoord);
139 nsSize containerSize = size.GetPhysicalSize(rtcWM);
140 for (nsIFrame* child : mFrames) {
141 // We reflowed the child with a dummy container size, as the true size
142 // was not yet known at that time.
143 LogicalPoint pos = child->GetLogicalPosition(rtcWM, dummyContainerSize);
144 // Adjust block position to account for minBCoord,
145 // then reposition child based on the true container width.
146 pos.B(rtcWM) -= minBCoord;
147 // Relative positioning hasn't happened yet.
148 // So MovePositionBy should not be used here.
149 child->SetPosition(rtcWM, pos, containerSize);
150 nsContainerFrame::PlaceFrameView(child);
152 aDesiredSize.SetSize(rtcWM, size);
153 } else {
154 // If this ruby text container is empty, size it as if there were
155 // an empty inline child inside.
156 // Border and padding are suppressed on ruby text container, so we
157 // create a dummy zero-sized borderPadding for setting BSize.
158 aDesiredSize.ISize(rtcWM) = mISize;
159 LogicalMargin borderPadding(rtcWM);
160 nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, borderPadding,
161 rtcWM, rtcWM);