Bumping manifests a=b2g-bump
[gecko.git] / layout / generic / nsRubyBaseContainerFrame.cpp
blob814a92357f671c9a38c4b4027787b770b76bd8db
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)
28 nsContainerFrame*
29 NS_NewRubyBaseContainerFrame(nsIPresShell* aPresShell,
30 nsStyleContext* aContext)
32 return new (aPresShell) nsRubyBaseContainerFrame(aContext);
36 //----------------------------------------------------------------------
38 // nsRubyBaseContainerFrame Method Implementations
39 // ===============================================
41 nsIAtom*
42 nsRubyBaseContainerFrame::GetType() const
44 return nsGkAtoms::rubyBaseContainerFrame;
47 #ifdef DEBUG_FRAME_DUMP
48 nsresult
49 nsRubyBaseContainerFrame::GetFrameName(nsAString& aResult) const
51 return MakeFrameName(NS_LITERAL_STRING("RubyBaseContainer"), aResult);
53 #endif
55 /* virtual */ bool
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);
65 if (rtcFrame) {
66 mTextContainers.AppendElement(rtcFrame);
70 void nsRubyBaseContainerFrame::ClearTextContainers() {
71 mTextContainers.Clear();
74 /* virtual */ bool
75 nsRubyBaseContainerFrame::CanContinueTextRun() const
77 return true;
80 /* virtual */ void
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) {
90 NS_ASSERTION(
91 aReflowState.mLineLayout,
92 "No line layout provided to RubyBaseContainerFrame reflow method.");
93 aStatus = NS_FRAME_COMPLETE;
94 return;
97 aStatus = NS_FRAME_COMPLETE;
98 nscoord isize = 0;
99 int baseNum = 0;
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");
126 continue;
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));
142 if (rtFrame) {
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;
152 } else {
153 spaceApart = leftoverSpace;
154 leftoverSpace = 0;
156 if (spaceApart > 0) {
157 aReflowState.mLineLayout->AdvanceICoord(spaceApart);
159 baseStart = aReflowState.mLineLayout->GetCurrentICoord();
161 bool pushedFrame;
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);
177 if (rtFrame) {
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,
186 rtcReflowState);
189 baseNum++;
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);
202 if (rtFrame) {
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,
212 rtcReflowState);
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);
218 baseNum++;
221 aDesiredSize.ISize(lineWM) = isize;
222 nsLayoutUtils::SetBSizeFromFontMetrics(this, aDesiredSize, aReflowState,
223 borderPadding, lineWM, frameWM);