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
);
50 void nsRubyTextContainerFrame::SetInitialChildList(ChildListID aListID
,
51 nsFrameList
&& aChildList
) {
52 nsContainerFrame::SetInitialChildList(aListID
, std::move(aChildList
));
53 if (aListID
== FrameChildListID::Principal
) {
59 void nsRubyTextContainerFrame::AppendFrames(ChildListID aListID
,
60 nsFrameList
&& aFrameList
) {
61 nsContainerFrame::AppendFrames(aListID
, std::move(aFrameList
));
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
));
75 void nsRubyTextContainerFrame::RemoveFrame(DestroyContext
& aContext
,
77 nsIFrame
* aOldFrame
) {
78 nsContainerFrame::RemoveFrame(aContext
, aListID
, aOldFrame
);
82 void nsRubyTextContainerFrame::UpdateSpanFlag() {
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.
95 AddStateBits(NS_RUBY_TEXT_CONTAINER_IS_SPAN
);
97 RemoveStateBits(NS_RUBY_TEXT_CONTAINER_IS_SPAN
);
102 void nsRubyTextContainerFrame::Reflow(nsPresContext
* aPresContext
,
103 ReflowOutput
& aDesiredSize
,
104 const ReflowInput
& aReflowInput
,
105 nsReflowStatus
& aStatus
) {
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
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
);
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
,