1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code is subject to the terms of the Mozilla Public License
4 * version 2.0 (the "License"). You can obtain a copy of the License at
5 * http://mozilla.org/MPL/2.0/. */
7 /* rendering object for CSS "display: ruby-base-container" */
9 #include "nsRubyBaseContainerFrame.h"
10 #include "nsLineLayout.h"
11 #include "nsPresContext.h"
12 #include "nsStyleContext.h"
13 #include "WritingModes.h"
15 using namespace mozilla
;
17 //----------------------------------------------------------------------
19 // Frame class boilerplate
20 // =======================
22 NS_QUERYFRAME_HEAD(nsRubyBaseContainerFrame
)
23 NS_QUERYFRAME_ENTRY(nsRubyBaseContainerFrame
)
24 NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame
)
26 NS_IMPL_FRAMEARENA_HELPERS(nsRubyBaseContainerFrame
)
29 NS_NewRubyBaseContainerFrame(nsIPresShell
* aPresShell
,
30 nsStyleContext
* aContext
)
32 return new (aPresShell
) nsRubyBaseContainerFrame(aContext
);
36 //----------------------------------------------------------------------
38 // nsRubyBaseContainerFrame Method Implementations
39 // ===============================================
42 nsRubyBaseContainerFrame::GetType() const
44 return nsGkAtoms::rubyBaseContainerFrame
;
47 #ifdef DEBUG_FRAME_DUMP
49 nsRubyBaseContainerFrame::GetFrameName(nsAString
& aResult
) const
51 return MakeFrameName(NS_LITERAL_STRING("RubyBaseContainer"), aResult
);
56 nsRubyBaseContainerFrame::IsFrameOfType(uint32_t aFlags
) const
58 return nsContainerFrame::IsFrameOfType(aFlags
&
59 ~(nsIFrame::eLineParticipant
));
62 void nsRubyBaseContainerFrame::AppendTextContainer(nsIFrame
* aFrame
)
64 nsRubyTextContainerFrame
* rtcFrame
= do_QueryFrame(aFrame
);
66 mTextContainers
.AppendElement(rtcFrame
);
70 void nsRubyBaseContainerFrame::ClearTextContainers() {
71 mTextContainers
.Clear();
75 nsRubyBaseContainerFrame::CanContinueTextRun() const
81 nsRubyBaseContainerFrame::Reflow(nsPresContext
* aPresContext
,
82 nsHTMLReflowMetrics
& aDesiredSize
,
83 const nsHTMLReflowState
& aReflowState
,
84 nsReflowStatus
& aStatus
)
86 DO_GLOBAL_REFLOW_COUNT("nsRubyBaseContainerFrame");
87 DISPLAY_REFLOW(aPresContext
, this, aReflowState
, aDesiredSize
, aStatus
);
89 if (!aReflowState
.mLineLayout
) {
91 aReflowState
.mLineLayout
,
92 "No line layout provided to RubyBaseContainerFrame reflow method.");
93 aStatus
= NS_FRAME_COMPLETE
;
97 aStatus
= NS_FRAME_COMPLETE
;
100 nscoord leftoverSpace
= 0;
101 nscoord spaceApart
= 0;
102 WritingMode lineWM
= aReflowState
.mLineLayout
->GetWritingMode();
103 WritingMode frameWM
= aReflowState
.GetWritingMode();
104 LogicalMargin borderPadding
=
105 aReflowState
.ComputedLogicalBorderPadding();
106 nscoord baseStart
= 0;
108 LogicalSize
availSize(lineWM
, aReflowState
.AvailableWidth(),
109 aReflowState
.AvailableHeight());
111 // Begin the line layout for each ruby text container in advance.
112 for (uint32_t i
= 0; i
< mTextContainers
.Length(); i
++) {
113 nsRubyTextContainerFrame
* rtcFrame
= mTextContainers
.ElementAt(i
);
114 nsHTMLReflowState
rtcReflowState(aPresContext
,
115 *aReflowState
.parentReflowState
,
116 rtcFrame
, availSize
);
117 rtcReflowState
.mLineLayout
= aReflowState
.mLineLayout
;
118 // FIXME: Avoid using/needing the rtcReflowState argument
119 rtcFrame
->BeginRTCLineLayout(aPresContext
, rtcReflowState
);
122 for (nsFrameList::Enumerator
e(mFrames
); !e
.AtEnd(); e
.Next()) {
123 nsIFrame
* rbFrame
= e
.get();
124 if (rbFrame
->GetType() != nsGkAtoms::rubyBaseFrame
) {
125 NS_ASSERTION(false, "Unrecognized child type for ruby base container");
129 nsReflowStatus frameReflowStatus
;
130 nsHTMLReflowMetrics
metrics(aReflowState
, aDesiredSize
.mFlags
);
132 // Determine if we need more spacing between bases in the inline direction
133 // depending on the inline size of the corresponding annotations
134 // FIXME: The use of GetPrefISize here and below is easier but not ideal. It
135 // would be better to use metrics from reflow.
136 nscoord prefWidth
= rbFrame
->GetPrefISize(aReflowState
.rendContext
);
137 nscoord textWidth
= 0;
139 for (uint32_t i
= 0; i
< mTextContainers
.Length(); i
++) {
140 nsRubyTextFrame
* rtFrame
= do_QueryFrame(mTextContainers
.ElementAt(i
)->
141 PrincipalChildList().FrameAt(baseNum
));
143 int newWidth
= rtFrame
->GetPrefISize(aReflowState
.rendContext
);
144 if (newWidth
> textWidth
) {
145 textWidth
= newWidth
;
149 if (textWidth
> prefWidth
) {
150 spaceApart
= std::max((textWidth
- prefWidth
) / 2, spaceApart
);
151 leftoverSpace
= spaceApart
;
153 spaceApart
= leftoverSpace
;
156 if (spaceApart
> 0) {
157 aReflowState
.mLineLayout
->AdvanceICoord(spaceApart
);
159 baseStart
= aReflowState
.mLineLayout
->GetCurrentICoord();
162 aReflowState
.mLineLayout
->ReflowFrame(rbFrame
, frameReflowStatus
,
163 &metrics
, pushedFrame
);
164 NS_ASSERTION(!pushedFrame
, "Ruby line breaking is not yet implemented");
166 isize
+= metrics
.ISize(lineWM
);
167 rbFrame
->SetSize(LogicalSize(lineWM
, metrics
.ISize(lineWM
),
168 metrics
.BSize(lineWM
)));
169 FinishReflowChild(rbFrame
, aPresContext
, metrics
, &aReflowState
, 0, 0,
170 NS_FRAME_NO_MOVE_FRAME
| NS_FRAME_NO_MOVE_VIEW
);
172 // Now reflow the ruby text boxes that correspond to this ruby base box.
173 for (uint32_t i
= 0; i
< mTextContainers
.Length(); i
++) {
174 nsRubyTextFrame
* rtFrame
= do_QueryFrame(mTextContainers
.ElementAt(i
)->
175 PrincipalChildList().FrameAt(baseNum
));
176 nsRubyTextContainerFrame
* rtcFrame
= mTextContainers
.ElementAt(i
);
178 nsHTMLReflowMetrics
rtcMetrics(*aReflowState
.parentReflowState
,
179 aDesiredSize
.mFlags
);
180 nsHTMLReflowState
rtcReflowState(aPresContext
,
181 *aReflowState
.parentReflowState
,
182 rtcFrame
, availSize
);
183 rtcReflowState
.mLineLayout
= rtcFrame
->GetLineLayout();
184 rtcFrame
->ReflowRubyTextFrame(rtFrame
, rbFrame
, baseStart
,
185 aPresContext
, rtcMetrics
,
192 // Reflow ruby annotations which do not have a corresponding ruby base box due
193 // to a ruby base shortage. According to the spec, an empty ruby base is
194 // assumed to exist for each of these annotations.
195 bool continueReflow
= true;
196 while (continueReflow
) {
197 continueReflow
= false;
198 for (uint32_t i
= 0; i
< mTextContainers
.Length(); i
++) {
199 nsRubyTextFrame
* rtFrame
= do_QueryFrame(mTextContainers
.ElementAt(i
)->
200 PrincipalChildList().FrameAt(baseNum
));
201 nsRubyTextContainerFrame
* rtcFrame
= mTextContainers
.ElementAt(i
);
203 continueReflow
= true;
204 nsHTMLReflowMetrics
rtcMetrics(*aReflowState
.parentReflowState
,
205 aDesiredSize
.mFlags
);
206 nsHTMLReflowState
rtcReflowState(aPresContext
,
207 *aReflowState
.parentReflowState
,
208 rtcFrame
, availSize
);
209 rtcReflowState
.mLineLayout
= rtcFrame
->GetLineLayout();
210 rtcFrame
->ReflowRubyTextFrame(rtFrame
, nullptr, baseStart
,
211 aPresContext
, rtcMetrics
,
213 // Update the inline coord to make space for subsequent ruby annotations
214 // (since there is no corresponding base inline size to use).
215 baseStart
+= rtcMetrics
.ISize(lineWM
);
221 aDesiredSize
.ISize(lineWM
) = isize
;
222 nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize
, aReflowState
,
223 borderPadding
, lineWM
, frameWM
);