Line data Source code
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/. */
6 :
7 : /* rendering object for CSS "display: ruby-text-container" */
8 :
9 : #include "nsRubyTextContainerFrame.h"
10 :
11 : #include "mozilla/UniquePtr.h"
12 : #include "mozilla/WritingModes.h"
13 : #include "nsLineLayout.h"
14 : #include "nsPresContext.h"
15 : #include "nsStyleContext.h"
16 :
17 : using namespace mozilla;
18 :
19 : //----------------------------------------------------------------------
20 :
21 : // Frame class boilerplate
22 : // =======================
23 :
24 0 : NS_QUERYFRAME_HEAD(nsRubyTextContainerFrame)
25 0 : NS_QUERYFRAME_ENTRY(nsRubyTextContainerFrame)
26 0 : NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
27 :
28 0 : NS_IMPL_FRAMEARENA_HELPERS(nsRubyTextContainerFrame)
29 :
30 : nsContainerFrame*
31 0 : NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell,
32 : nsStyleContext* aContext)
33 : {
34 0 : return new (aPresShell) nsRubyTextContainerFrame(aContext);
35 : }
36 :
37 :
38 : //----------------------------------------------------------------------
39 :
40 : // nsRubyTextContainerFrame Method Implementations
41 : // ===============================================
42 :
43 : #ifdef DEBUG_FRAME_DUMP
44 : nsresult
45 0 : nsRubyTextContainerFrame::GetFrameName(nsAString& aResult) const
46 : {
47 0 : return MakeFrameName(NS_LITERAL_STRING("RubyTextContainer"), aResult);
48 : }
49 : #endif
50 :
51 : /* virtual */ bool
52 0 : nsRubyTextContainerFrame::IsFrameOfType(uint32_t aFlags) const
53 : {
54 0 : if (aFlags & eSupportsCSSTransforms) {
55 0 : return false;
56 : }
57 0 : return nsContainerFrame::IsFrameOfType(aFlags);
58 : }
59 :
60 : /* virtual */ void
61 0 : nsRubyTextContainerFrame::SetInitialChildList(ChildListID aListID,
62 : nsFrameList& aChildList)
63 : {
64 0 : nsContainerFrame::SetInitialChildList(aListID, aChildList);
65 0 : if (aListID == kPrincipalList) {
66 0 : UpdateSpanFlag();
67 : }
68 0 : }
69 :
70 : /* virtual */ void
71 0 : nsRubyTextContainerFrame::AppendFrames(ChildListID aListID,
72 : nsFrameList& aFrameList)
73 : {
74 0 : nsContainerFrame::AppendFrames(aListID, aFrameList);
75 0 : UpdateSpanFlag();
76 0 : }
77 :
78 : /* virtual */ void
79 0 : nsRubyTextContainerFrame::InsertFrames(ChildListID aListID,
80 : nsIFrame* aPrevFrame,
81 : nsFrameList& aFrameList)
82 : {
83 0 : nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList);
84 0 : UpdateSpanFlag();
85 0 : }
86 :
87 : /* virtual */ void
88 0 : nsRubyTextContainerFrame::RemoveFrame(ChildListID aListID,
89 : nsIFrame* aOldFrame)
90 : {
91 0 : nsContainerFrame::RemoveFrame(aListID, aOldFrame);
92 0 : UpdateSpanFlag();
93 0 : }
94 :
95 : void
96 0 : nsRubyTextContainerFrame::UpdateSpanFlag()
97 : {
98 0 : bool isSpan = false;
99 : // The continuation checks are safe here because spans never break.
100 0 : if (!GetPrevContinuation() && !GetNextContinuation()) {
101 0 : nsIFrame* onlyChild = mFrames.OnlyChild();
102 0 : if (onlyChild && onlyChild->IsPseudoFrame(GetContent())) {
103 : // Per CSS Ruby spec, if the only child of an rtc frame is
104 : // a pseudo rt frame, it spans all bases in the segment.
105 0 : isSpan = true;
106 : }
107 : }
108 :
109 0 : if (isSpan) {
110 0 : AddStateBits(NS_RUBY_TEXT_CONTAINER_IS_SPAN);
111 : } else {
112 0 : RemoveStateBits(NS_RUBY_TEXT_CONTAINER_IS_SPAN);
113 : }
114 0 : }
115 :
116 : /* virtual */ void
117 0 : nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
118 : ReflowOutput& aDesiredSize,
119 : const ReflowInput& aReflowInput,
120 : nsReflowStatus& aStatus)
121 : {
122 0 : MarkInReflow();
123 0 : DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame");
124 0 : DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
125 :
126 : // Although a ruby text container may have continuations, returning
127 : // complete reflow status is still safe, since its parent, ruby frame,
128 : // ignores the status, and continuations of the ruby base container
129 : // will take care of our continuations.
130 0 : aStatus.Reset();
131 0 : WritingMode lineWM = aReflowInput.mLineLayout->GetWritingMode();
132 :
133 0 : nscoord minBCoord = nscoord_MAX;
134 0 : nscoord maxBCoord = nscoord_MIN;
135 : // The container size is not yet known, so we use a dummy (0, 0) size.
136 : // The block-dir position will be corrected below after containerSize
137 : // is finalized.
138 0 : const nsSize dummyContainerSize;
139 0 : for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
140 0 : nsIFrame* child = e.get();
141 0 : MOZ_ASSERT(child->IsRubyTextFrame());
142 0 : LogicalRect rect = child->GetLogicalRect(lineWM, dummyContainerSize);
143 0 : LogicalMargin margin = child->GetLogicalUsedMargin(lineWM);
144 0 : nscoord blockStart = rect.BStart(lineWM) - margin.BStart(lineWM);
145 0 : minBCoord = std::min(minBCoord, blockStart);
146 0 : nscoord blockEnd = rect.BEnd(lineWM) + margin.BEnd(lineWM);
147 0 : maxBCoord = std::max(maxBCoord, blockEnd);
148 : }
149 :
150 0 : LogicalSize size(lineWM, mISize, 0);
151 0 : if (!mFrames.IsEmpty()) {
152 0 : if (MOZ_UNLIKELY(minBCoord > maxBCoord)) {
153 : // XXX When bug 765861 gets fixed, this warning should be upgraded.
154 0 : NS_WARNING("bad block coord");
155 0 : minBCoord = maxBCoord = 0;
156 : }
157 0 : size.BSize(lineWM) = maxBCoord - minBCoord;
158 0 : nsSize containerSize = size.GetPhysicalSize(lineWM);
159 0 : for (nsFrameList::Enumerator e(mFrames); !e.AtEnd(); e.Next()) {
160 0 : nsIFrame* child = e.get();
161 : // We reflowed the child with a dummy container size, as the true size
162 : // was not yet known at that time.
163 0 : LogicalPoint pos = child->GetLogicalPosition(lineWM, dummyContainerSize);
164 : // Adjust block position to account for minBCoord,
165 : // then reposition child based on the true container width.
166 0 : pos.B(lineWM) -= minBCoord;
167 : // Relative positioning hasn't happened yet.
168 : // So MovePositionBy should not be used here.
169 0 : child->SetPosition(lineWM, pos, containerSize);
170 0 : nsContainerFrame::PlaceFrameView(child);
171 : }
172 : }
173 :
174 0 : aDesiredSize.SetSize(lineWM, size);
175 0 : }
|