1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : // YY need to pass isMultiple before create called
39 :
40 : #include "nsBoxFrame.h"
41 : #include "nsCSSRendering.h"
42 : #include "nsRenderingContext.h"
43 : #include "nsStyleContext.h"
44 : #include "nsDisplayList.h"
45 :
46 0 : class nsGroupBoxFrame : public nsBoxFrame {
47 : public:
48 : NS_DECL_FRAMEARENA_HELPERS
49 :
50 0 : nsGroupBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext):
51 0 : nsBoxFrame(aShell, aContext) {}
52 :
53 : NS_IMETHOD GetBorderAndPadding(nsMargin& aBorderAndPadding);
54 :
55 : NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
56 : const nsRect& aDirtyRect,
57 : const nsDisplayListSet& aLists);
58 :
59 : #ifdef DEBUG
60 0 : NS_IMETHOD GetFrameName(nsAString& aResult) const {
61 0 : return MakeFrameName(NS_LITERAL_STRING("GroupBoxFrame"), aResult);
62 : }
63 : #endif
64 :
65 0 : virtual bool HonorPrintBackgroundSettings() { return false; }
66 :
67 : void PaintBorderBackground(nsRenderingContext& aRenderingContext,
68 : nsPoint aPt, const nsRect& aDirtyRect);
69 :
70 : // make sure we our kids get our orient and align instead of us.
71 : // our child box has no content node so it will search for a parent with one.
72 : // that will be us.
73 0 : virtual void GetInitialOrientation(bool& aHorizontal) { aHorizontal = false; }
74 0 : virtual bool GetInitialHAlignment(Halignment& aHalign) { aHalign = hAlign_Left; return true; }
75 0 : virtual bool GetInitialVAlignment(Valignment& aValign) { aValign = vAlign_Top; return true; }
76 0 : virtual bool GetInitialAutoStretch(bool& aStretch) { aStretch = true; return true; }
77 :
78 : nsIBox* GetCaptionBox(nsPresContext* aPresContext, nsRect& aCaptionRect);
79 : };
80 :
81 : /*
82 : class nsGroupBoxInnerFrame : public nsBoxFrame {
83 : public:
84 :
85 : nsGroupBoxInnerFrame(nsIPresShell* aShell, nsStyleContext* aContext):
86 : nsBoxFrame(aShell, aContext) {}
87 :
88 :
89 : #ifdef DEBUG
90 : NS_IMETHOD GetFrameName(nsString& aResult) const {
91 : return MakeFrameName("GroupBoxFrameInner", aResult);
92 : }
93 : #endif
94 :
95 : // we are always flexible
96 : virtual bool GetDefaultFlex(PRInt32& aFlex) { aFlex = 1; return true; }
97 :
98 : };
99 : */
100 :
101 : nsIFrame*
102 0 : NS_NewGroupBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
103 : {
104 0 : return new (aPresShell) nsGroupBoxFrame(aPresShell, aContext);
105 : }
106 :
107 0 : NS_IMPL_FRAMEARENA_HELPERS(nsGroupBoxFrame)
108 :
109 : class nsDisplayXULGroupBackground : public nsDisplayItem {
110 : public:
111 0 : nsDisplayXULGroupBackground(nsDisplayListBuilder* aBuilder,
112 : nsGroupBoxFrame* aFrame) :
113 0 : nsDisplayItem(aBuilder, aFrame) {
114 0 : MOZ_COUNT_CTOR(nsDisplayXULGroupBackground);
115 0 : }
116 : #ifdef NS_BUILD_REFCNT_LOGGING
117 0 : virtual ~nsDisplayXULGroupBackground() {
118 0 : MOZ_COUNT_DTOR(nsDisplayXULGroupBackground);
119 0 : }
120 : #endif
121 :
122 0 : virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
123 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {
124 0 : aOutFrames->AppendElement(mFrame);
125 0 : }
126 : virtual void Paint(nsDisplayListBuilder* aBuilder,
127 : nsRenderingContext* aCtx);
128 0 : NS_DISPLAY_DECL_NAME("XULGroupBackground", TYPE_XUL_GROUP_BACKGROUND)
129 : };
130 :
131 : void
132 0 : nsDisplayXULGroupBackground::Paint(nsDisplayListBuilder* aBuilder,
133 : nsRenderingContext* aCtx)
134 : {
135 : static_cast<nsGroupBoxFrame*>(mFrame)->
136 0 : PaintBorderBackground(*aCtx, ToReferenceFrame(), mVisibleRect);
137 0 : }
138 :
139 : NS_IMETHODIMP
140 0 : nsGroupBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
141 : const nsRect& aDirtyRect,
142 : const nsDisplayListSet& aLists)
143 : {
144 : // Paint our background and border
145 0 : if (IsVisibleForPainting(aBuilder)) {
146 : nsresult rv = aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
147 0 : nsDisplayXULGroupBackground(aBuilder, this));
148 0 : NS_ENSURE_SUCCESS(rv, rv);
149 :
150 0 : rv = DisplayOutline(aBuilder, aLists);
151 0 : NS_ENSURE_SUCCESS(rv, rv);
152 : }
153 :
154 0 : return BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists);
155 : // REVIEW: Debug borders now painted by nsFrame::BuildDisplayListForChild
156 : }
157 :
158 : void
159 0 : nsGroupBoxFrame::PaintBorderBackground(nsRenderingContext& aRenderingContext,
160 : nsPoint aPt, const nsRect& aDirtyRect) {
161 0 : PRIntn skipSides = 0;
162 0 : const nsStyleBorder* borderStyleData = GetStyleBorder();
163 0 : const nsMargin& border = borderStyleData->GetActualBorder();
164 0 : nscoord yoff = 0;
165 0 : nsPresContext* presContext = PresContext();
166 :
167 0 : nsRect groupRect;
168 0 : nsIBox* groupBox = GetCaptionBox(presContext, groupRect);
169 :
170 0 : if (groupBox) {
171 : // if the border is smaller than the legend. Move the border down
172 : // to be centered on the legend.
173 0 : nsMargin groupMargin;
174 0 : groupBox->GetStyleMargin()->GetMargin(groupMargin);
175 0 : groupRect.Inflate(groupMargin);
176 :
177 0 : if (border.top < groupRect.height)
178 0 : yoff = (groupRect.height - border.top)/2 + groupRect.y;
179 : }
180 :
181 0 : nsRect rect(aPt.x, aPt.y + yoff, mRect.width, mRect.height - yoff);
182 :
183 0 : groupRect += aPt;
184 :
185 : nsCSSRendering::PaintBackground(presContext, aRenderingContext, this,
186 : aDirtyRect, rect,
187 0 : nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES);
188 :
189 0 : if (groupBox) {
190 :
191 : // we should probably use PaintBorderEdges to do this but for now just use clipping
192 : // to achieve the same effect.
193 :
194 : // draw left side
195 0 : nsRect clipRect(rect);
196 0 : clipRect.width = groupRect.x - rect.x;
197 0 : clipRect.height = border.top;
198 :
199 0 : aRenderingContext.PushState();
200 0 : aRenderingContext.IntersectClip(clipRect);
201 : nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
202 0 : aDirtyRect, rect, mStyleContext, skipSides);
203 :
204 0 : aRenderingContext.PopState();
205 :
206 :
207 : // draw right side
208 0 : clipRect = rect;
209 0 : clipRect.x = groupRect.XMost();
210 0 : clipRect.width = rect.XMost() - groupRect.XMost();
211 0 : clipRect.height = border.top;
212 :
213 0 : aRenderingContext.PushState();
214 0 : aRenderingContext.IntersectClip(clipRect);
215 : nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
216 0 : aDirtyRect, rect, mStyleContext, skipSides);
217 :
218 0 : aRenderingContext.PopState();
219 :
220 :
221 :
222 : // draw bottom
223 :
224 0 : clipRect = rect;
225 0 : clipRect.y += border.top;
226 0 : clipRect.height = mRect.height - (yoff + border.top);
227 :
228 0 : aRenderingContext.PushState();
229 0 : aRenderingContext.IntersectClip(clipRect);
230 : nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
231 0 : aDirtyRect, rect, mStyleContext, skipSides);
232 :
233 0 : aRenderingContext.PopState();
234 :
235 : } else {
236 : nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
237 0 : aDirtyRect, nsRect(aPt, GetSize()),
238 0 : mStyleContext, skipSides);
239 : }
240 0 : }
241 :
242 : nsIBox*
243 0 : nsGroupBoxFrame::GetCaptionBox(nsPresContext* aPresContext, nsRect& aCaptionRect)
244 : {
245 : // first child is our grouped area
246 0 : nsIBox* box = GetChildBox();
247 :
248 : // no area fail.
249 0 : if (!box)
250 0 : return nsnull;
251 :
252 : // get the first child in the grouped area, that is the caption
253 0 : box = box->GetChildBox();
254 :
255 : // nothing in the area? fail
256 0 : if (!box)
257 0 : return nsnull;
258 :
259 : // now get the caption itself. It is in the caption frame.
260 0 : nsIBox* child = box->GetChildBox();
261 :
262 0 : if (child) {
263 : // convert to our coordinates.
264 0 : nsRect parentRect(box->GetRect());
265 0 : aCaptionRect = child->GetRect();
266 0 : aCaptionRect.x += parentRect.x;
267 0 : aCaptionRect.y += parentRect.y;
268 : }
269 :
270 0 : return child;
271 : }
272 :
273 : NS_IMETHODIMP
274 0 : nsGroupBoxFrame::GetBorderAndPadding(nsMargin& aBorderAndPadding)
275 : {
276 0 : aBorderAndPadding.SizeTo(0,0,0,0);
277 0 : return NS_OK;
278 : }
279 :
|