|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 // YY need to pass isMultiple before create called |
|
7 |
|
8 #include "nsBoxFrame.h" |
|
9 #include "nsCSSRendering.h" |
|
10 #include "nsRenderingContext.h" |
|
11 #include "nsStyleContext.h" |
|
12 #include "nsDisplayList.h" |
|
13 |
|
14 class nsGroupBoxFrame : public nsBoxFrame { |
|
15 public: |
|
16 NS_DECL_FRAMEARENA_HELPERS |
|
17 |
|
18 nsGroupBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext): |
|
19 nsBoxFrame(aShell, aContext) {} |
|
20 |
|
21 virtual nsresult GetBorderAndPadding(nsMargin& aBorderAndPadding); |
|
22 |
|
23 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder, |
|
24 const nsRect& aDirtyRect, |
|
25 const nsDisplayListSet& aLists) MOZ_OVERRIDE; |
|
26 |
|
27 #ifdef DEBUG_FRAME_DUMP |
|
28 virtual nsresult GetFrameName(nsAString& aResult) const { |
|
29 return MakeFrameName(NS_LITERAL_STRING("GroupBoxFrame"), aResult); |
|
30 } |
|
31 #endif |
|
32 |
|
33 virtual bool HonorPrintBackgroundSettings() { return false; } |
|
34 |
|
35 void PaintBorderBackground(nsRenderingContext& aRenderingContext, |
|
36 nsPoint aPt, const nsRect& aDirtyRect); |
|
37 |
|
38 // make sure we our kids get our orient and align instead of us. |
|
39 // our child box has no content node so it will search for a parent with one. |
|
40 // that will be us. |
|
41 virtual void GetInitialOrientation(bool& aHorizontal) { aHorizontal = false; } |
|
42 virtual bool GetInitialHAlignment(Halignment& aHalign) { aHalign = hAlign_Left; return true; } |
|
43 virtual bool GetInitialVAlignment(Valignment& aValign) { aValign = vAlign_Top; return true; } |
|
44 virtual bool GetInitialAutoStretch(bool& aStretch) { aStretch = true; return true; } |
|
45 |
|
46 nsIFrame* GetCaptionBox(nsPresContext* aPresContext, nsRect& aCaptionRect); |
|
47 }; |
|
48 |
|
49 /* |
|
50 class nsGroupBoxInnerFrame : public nsBoxFrame { |
|
51 public: |
|
52 |
|
53 nsGroupBoxInnerFrame(nsIPresShell* aShell, nsStyleContext* aContext): |
|
54 nsBoxFrame(aShell, aContext) {} |
|
55 |
|
56 |
|
57 #ifdef DEBUG_FRAME_DUMP |
|
58 NS_IMETHOD GetFrameName(nsString& aResult) const { |
|
59 return MakeFrameName("GroupBoxFrameInner", aResult); |
|
60 } |
|
61 #endif |
|
62 |
|
63 // we are always flexible |
|
64 virtual bool GetDefaultFlex(int32_t& aFlex) { aFlex = 1; return true; } |
|
65 |
|
66 }; |
|
67 */ |
|
68 |
|
69 nsIFrame* |
|
70 NS_NewGroupBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) |
|
71 { |
|
72 return new (aPresShell) nsGroupBoxFrame(aPresShell, aContext); |
|
73 } |
|
74 |
|
75 NS_IMPL_FRAMEARENA_HELPERS(nsGroupBoxFrame) |
|
76 |
|
77 class nsDisplayXULGroupBackground : public nsDisplayItem { |
|
78 public: |
|
79 nsDisplayXULGroupBackground(nsDisplayListBuilder* aBuilder, |
|
80 nsGroupBoxFrame* aFrame) : |
|
81 nsDisplayItem(aBuilder, aFrame) { |
|
82 MOZ_COUNT_CTOR(nsDisplayXULGroupBackground); |
|
83 } |
|
84 #ifdef NS_BUILD_REFCNT_LOGGING |
|
85 virtual ~nsDisplayXULGroupBackground() { |
|
86 MOZ_COUNT_DTOR(nsDisplayXULGroupBackground); |
|
87 } |
|
88 #endif |
|
89 |
|
90 virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, |
|
91 HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) { |
|
92 aOutFrames->AppendElement(mFrame); |
|
93 } |
|
94 virtual void Paint(nsDisplayListBuilder* aBuilder, |
|
95 nsRenderingContext* aCtx); |
|
96 NS_DISPLAY_DECL_NAME("XULGroupBackground", TYPE_XUL_GROUP_BACKGROUND) |
|
97 }; |
|
98 |
|
99 void |
|
100 nsDisplayXULGroupBackground::Paint(nsDisplayListBuilder* aBuilder, |
|
101 nsRenderingContext* aCtx) |
|
102 { |
|
103 static_cast<nsGroupBoxFrame*>(mFrame)-> |
|
104 PaintBorderBackground(*aCtx, ToReferenceFrame(), mVisibleRect); |
|
105 } |
|
106 |
|
107 void |
|
108 nsGroupBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, |
|
109 const nsRect& aDirtyRect, |
|
110 const nsDisplayListSet& aLists) |
|
111 { |
|
112 // Paint our background and border |
|
113 if (IsVisibleForPainting(aBuilder)) { |
|
114 aLists.BorderBackground()->AppendNewToTop(new (aBuilder) |
|
115 nsDisplayXULGroupBackground(aBuilder, this)); |
|
116 |
|
117 DisplayOutline(aBuilder, aLists); |
|
118 } |
|
119 |
|
120 BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists); |
|
121 } |
|
122 |
|
123 void |
|
124 nsGroupBoxFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext, |
|
125 nsPoint aPt, const nsRect& aDirtyRect) { |
|
126 int skipSides = 0; |
|
127 const nsStyleBorder* borderStyleData = StyleBorder(); |
|
128 const nsMargin& border = borderStyleData->GetComputedBorder(); |
|
129 nscoord yoff = 0; |
|
130 nsPresContext* presContext = PresContext(); |
|
131 |
|
132 nsRect groupRect; |
|
133 nsIFrame* groupBox = GetCaptionBox(presContext, groupRect); |
|
134 |
|
135 if (groupBox) { |
|
136 // if the border is smaller than the legend. Move the border down |
|
137 // to be centered on the legend. |
|
138 nsMargin groupMargin; |
|
139 groupBox->StyleMargin()->GetMargin(groupMargin); |
|
140 groupRect.Inflate(groupMargin); |
|
141 |
|
142 if (border.top < groupRect.height) |
|
143 yoff = (groupRect.height - border.top)/2 + groupRect.y; |
|
144 } |
|
145 |
|
146 nsRect rect(aPt.x, aPt.y + yoff, mRect.width, mRect.height - yoff); |
|
147 |
|
148 groupRect += aPt; |
|
149 |
|
150 nsCSSRendering::PaintBackground(presContext, aRenderingContext, this, |
|
151 aDirtyRect, rect, |
|
152 nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES); |
|
153 |
|
154 if (groupBox) { |
|
155 |
|
156 // we should probably use PaintBorderEdges to do this but for now just use clipping |
|
157 // to achieve the same effect. |
|
158 |
|
159 // draw left side |
|
160 nsRect clipRect(rect); |
|
161 clipRect.width = groupRect.x - rect.x; |
|
162 clipRect.height = border.top; |
|
163 |
|
164 aRenderingContext.PushState(); |
|
165 aRenderingContext.IntersectClip(clipRect); |
|
166 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, |
|
167 aDirtyRect, rect, mStyleContext, skipSides); |
|
168 |
|
169 aRenderingContext.PopState(); |
|
170 |
|
171 |
|
172 // draw right side |
|
173 clipRect = rect; |
|
174 clipRect.x = groupRect.XMost(); |
|
175 clipRect.width = rect.XMost() - groupRect.XMost(); |
|
176 clipRect.height = border.top; |
|
177 |
|
178 aRenderingContext.PushState(); |
|
179 aRenderingContext.IntersectClip(clipRect); |
|
180 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, |
|
181 aDirtyRect, rect, mStyleContext, skipSides); |
|
182 |
|
183 aRenderingContext.PopState(); |
|
184 |
|
185 |
|
186 |
|
187 // draw bottom |
|
188 |
|
189 clipRect = rect; |
|
190 clipRect.y += border.top; |
|
191 clipRect.height = mRect.height - (yoff + border.top); |
|
192 |
|
193 aRenderingContext.PushState(); |
|
194 aRenderingContext.IntersectClip(clipRect); |
|
195 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, |
|
196 aDirtyRect, rect, mStyleContext, skipSides); |
|
197 |
|
198 aRenderingContext.PopState(); |
|
199 |
|
200 } else { |
|
201 nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, |
|
202 aDirtyRect, nsRect(aPt, GetSize()), |
|
203 mStyleContext, skipSides); |
|
204 } |
|
205 } |
|
206 |
|
207 nsIFrame* |
|
208 nsGroupBoxFrame::GetCaptionBox(nsPresContext* aPresContext, nsRect& aCaptionRect) |
|
209 { |
|
210 // first child is our grouped area |
|
211 nsIFrame* box = GetChildBox(); |
|
212 |
|
213 // no area fail. |
|
214 if (!box) |
|
215 return nullptr; |
|
216 |
|
217 // get the first child in the grouped area, that is the caption |
|
218 box = box->GetChildBox(); |
|
219 |
|
220 // nothing in the area? fail |
|
221 if (!box) |
|
222 return nullptr; |
|
223 |
|
224 // now get the caption itself. It is in the caption frame. |
|
225 nsIFrame* child = box->GetChildBox(); |
|
226 |
|
227 if (child) { |
|
228 // convert to our coordinates. |
|
229 nsRect parentRect(box->GetRect()); |
|
230 aCaptionRect = child->GetRect(); |
|
231 aCaptionRect.x += parentRect.x; |
|
232 aCaptionRect.y += parentRect.y; |
|
233 } |
|
234 |
|
235 return child; |
|
236 } |
|
237 |
|
238 nsresult |
|
239 nsGroupBoxFrame::GetBorderAndPadding(nsMargin& aBorderAndPadding) |
|
240 { |
|
241 aBorderAndPadding.SizeTo(0,0,0,0); |
|
242 return NS_OK; |
|
243 } |
|
244 |