Line data Source code
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 :
10 : #include "gfxContext.h"
11 : #include "mozilla/gfx/2D.h"
12 : #include "nsCSSRendering.h"
13 : #include "nsLayoutUtils.h"
14 : #include "nsStyleContext.h"
15 : #include "nsDisplayList.h"
16 :
17 : using namespace mozilla;
18 : using namespace mozilla::gfx;
19 : using namespace mozilla::image;
20 :
21 0 : class nsGroupBoxFrame final : public nsBoxFrame
22 : {
23 : public:
24 0 : NS_DECL_FRAMEARENA_HELPERS(nsGroupBoxFrame)
25 :
26 0 : explicit nsGroupBoxFrame(nsStyleContext* aContext):
27 0 : nsBoxFrame(aContext, kClassID) {}
28 :
29 : virtual nsresult GetXULBorderAndPadding(nsMargin& aBorderAndPadding) override;
30 :
31 : virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
32 : const nsRect& aDirtyRect,
33 : const nsDisplayListSet& aLists) override;
34 :
35 : #ifdef DEBUG_FRAME_DUMP
36 0 : virtual nsresult GetFrameName(nsAString& aResult) const override {
37 0 : return MakeFrameName(NS_LITERAL_STRING("GroupBoxFrame"), aResult);
38 : }
39 : #endif
40 :
41 0 : virtual bool HonorPrintBackgroundSettings() override { return false; }
42 :
43 : DrawResult PaintBorder(gfxContext& aRenderingContext,
44 : nsPoint aPt,
45 : const nsRect& aDirtyRect);
46 : nsRect GetBackgroundRectRelativeToSelf(nscoord* aOutYOffset = nullptr, nsRect* aOutGroupRect = nullptr);
47 :
48 : // make sure we our kids get our orient and align instead of us.
49 : // our child box has no content node so it will search for a parent with one.
50 : // that will be us.
51 0 : virtual void GetInitialOrientation(bool& aHorizontal) override { aHorizontal = false; }
52 0 : virtual bool GetInitialHAlignment(Halignment& aHalign) override { aHalign = hAlign_Left; return true; }
53 0 : virtual bool GetInitialVAlignment(Valignment& aValign) override { aValign = vAlign_Top; return true; }
54 0 : virtual bool GetInitialAutoStretch(bool& aStretch) override { aStretch = true; return true; }
55 :
56 : nsIFrame* GetCaptionBox(nsRect& aCaptionRect);
57 : };
58 :
59 : /*
60 : class nsGroupBoxInnerFrame : public nsBoxFrame {
61 : public:
62 :
63 : nsGroupBoxInnerFrame(nsIPresShell* aShell, nsStyleContext* aContext):
64 : nsBoxFrame(aShell, aContext) {}
65 :
66 :
67 : #ifdef DEBUG_FRAME_DUMP
68 : NS_IMETHOD GetFrameName(nsString& aResult) const {
69 : return MakeFrameName("GroupBoxFrameInner", aResult);
70 : }
71 : #endif
72 :
73 : // we are always flexible
74 : virtual bool GetDefaultFlex(int32_t& aFlex) { aFlex = 1; return true; }
75 :
76 : };
77 : */
78 :
79 : nsIFrame*
80 0 : NS_NewGroupBoxFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
81 : {
82 0 : return new (aPresShell) nsGroupBoxFrame(aContext);
83 : }
84 :
85 0 : NS_IMPL_FRAMEARENA_HELPERS(nsGroupBoxFrame)
86 :
87 : class nsDisplayXULGroupBorder final : public nsDisplayItem
88 : {
89 : public:
90 0 : nsDisplayXULGroupBorder(nsDisplayListBuilder* aBuilder,
91 0 : nsGroupBoxFrame* aFrame) :
92 0 : nsDisplayItem(aBuilder, aFrame) {
93 0 : MOZ_COUNT_CTOR(nsDisplayXULGroupBorder);
94 0 : }
95 : #ifdef NS_BUILD_REFCNT_LOGGING
96 0 : virtual ~nsDisplayXULGroupBorder() {
97 0 : MOZ_COUNT_DTOR(nsDisplayXULGroupBorder);
98 0 : }
99 : #endif
100 :
101 : nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
102 : void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
103 : const nsDisplayItemGeometry* aGeometry,
104 : nsRegion *aInvalidRegion) override;
105 0 : virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
106 : HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override {
107 0 : aOutFrames->AppendElement(mFrame);
108 0 : }
109 : virtual void Paint(nsDisplayListBuilder* aBuilder,
110 : gfxContext* aCtx) override;
111 0 : NS_DISPLAY_DECL_NAME("XULGroupBackground", TYPE_XUL_GROUP_BACKGROUND)
112 : };
113 :
114 : nsDisplayItemGeometry*
115 0 : nsDisplayXULGroupBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
116 : {
117 0 : return new nsDisplayItemGenericImageGeometry(this, aBuilder);
118 : }
119 :
120 : void
121 0 : nsDisplayXULGroupBorder::ComputeInvalidationRegion(
122 : nsDisplayListBuilder* aBuilder,
123 : const nsDisplayItemGeometry* aGeometry,
124 : nsRegion* aInvalidRegion)
125 : {
126 : auto geometry =
127 0 : static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
128 :
129 0 : if (aBuilder->ShouldSyncDecodeImages() &&
130 0 : geometry->ShouldInvalidateToSyncDecodeImages()) {
131 : bool snap;
132 0 : aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
133 : }
134 :
135 0 : nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
136 0 : }
137 :
138 : void
139 0 : nsDisplayXULGroupBorder::Paint(nsDisplayListBuilder* aBuilder,
140 : gfxContext* aCtx)
141 : {
142 0 : DrawResult result = static_cast<nsGroupBoxFrame*>(mFrame)
143 0 : ->PaintBorder(*aCtx, ToReferenceFrame(), mVisibleRect);
144 :
145 0 : nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
146 0 : }
147 :
148 : void
149 0 : nsGroupBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
150 : const nsRect& aDirtyRect,
151 : const nsDisplayListSet& aLists)
152 : {
153 : // Paint our background and border
154 0 : if (IsVisibleForPainting(aBuilder)) {
155 0 : nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
156 0 : aBuilder, this, GetBackgroundRectRelativeToSelf(),
157 0 : aLists.BorderBackground());
158 0 : aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
159 0 : nsDisplayXULGroupBorder(aBuilder, this));
160 :
161 0 : DisplayOutline(aBuilder, aLists);
162 : }
163 :
164 0 : BuildDisplayListForChildren(aBuilder, aDirtyRect, aLists);
165 0 : }
166 :
167 : nsRect
168 0 : nsGroupBoxFrame::GetBackgroundRectRelativeToSelf(nscoord* aOutYOffset, nsRect* aOutGroupRect)
169 : {
170 0 : const nsMargin& border = StyleBorder()->GetComputedBorder();
171 :
172 0 : nsRect groupRect;
173 0 : nsIFrame* groupBox = GetCaptionBox(groupRect);
174 :
175 0 : nscoord yoff = 0;
176 0 : if (groupBox) {
177 : // If the border is smaller than the legend, move the border down
178 : // to be centered on the legend.
179 0 : nsMargin groupMargin;
180 0 : groupBox->StyleMargin()->GetMargin(groupMargin);
181 0 : groupRect.Inflate(groupMargin);
182 :
183 0 : if (border.top < groupRect.height) {
184 0 : yoff = (groupRect.height - border.top) / 2 + groupRect.y;
185 : }
186 : }
187 :
188 0 : if (aOutYOffset) {
189 0 : *aOutYOffset = yoff;
190 : }
191 0 : if (aOutGroupRect) {
192 0 : *aOutGroupRect = groupRect;
193 : }
194 :
195 0 : return nsRect(0, yoff, mRect.width, mRect.height - yoff);
196 : }
197 :
198 : DrawResult
199 0 : nsGroupBoxFrame::PaintBorder(gfxContext& aRenderingContext,
200 : nsPoint aPt, const nsRect& aDirtyRect) {
201 :
202 0 : DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
203 :
204 0 : Sides skipSides;
205 0 : const nsStyleBorder* borderStyleData = StyleBorder();
206 0 : const nsMargin& border = borderStyleData->GetComputedBorder();
207 0 : nsPresContext* presContext = PresContext();
208 :
209 0 : nsRect groupRect;
210 0 : nsIFrame* groupBox = GetCaptionBox(groupRect);
211 :
212 0 : nscoord yoff = 0;
213 0 : nsRect rect = GetBackgroundRectRelativeToSelf(&yoff, &groupRect) + aPt;
214 0 : groupRect += aPt;
215 :
216 0 : DrawResult result = DrawResult::SUCCESS;
217 0 : if (groupBox) {
218 0 : int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
219 :
220 : // we should probably use PaintBorderEdges to do this but for now just use clipping
221 : // to achieve the same effect.
222 :
223 : // draw left side
224 0 : nsRect clipRect(rect);
225 0 : clipRect.width = groupRect.x - rect.x;
226 0 : clipRect.height = border.top;
227 :
228 0 : aRenderingContext.Save();
229 : aRenderingContext.Clip(
230 0 : NSRectToSnappedRect(clipRect, appUnitsPerDevPixel, *drawTarget));
231 : result &=
232 : nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
233 : aDirtyRect, rect, mStyleContext,
234 0 : PaintBorderFlags::SYNC_DECODE_IMAGES, skipSides);
235 0 : aRenderingContext.Restore();
236 :
237 : // draw right side
238 0 : clipRect = rect;
239 0 : clipRect.x = groupRect.XMost();
240 0 : clipRect.width = rect.XMost() - groupRect.XMost();
241 0 : clipRect.height = border.top;
242 :
243 0 : aRenderingContext.Save();
244 : aRenderingContext.Clip(
245 0 : NSRectToSnappedRect(clipRect, appUnitsPerDevPixel, *drawTarget));
246 : result &=
247 : nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
248 : aDirtyRect, rect, mStyleContext,
249 0 : PaintBorderFlags::SYNC_DECODE_IMAGES, skipSides);
250 :
251 0 : aRenderingContext.Restore();
252 : // draw bottom
253 :
254 0 : clipRect = rect;
255 0 : clipRect.y += border.top;
256 0 : clipRect.height = mRect.height - (yoff + border.top);
257 :
258 0 : aRenderingContext.Save();
259 : aRenderingContext.Clip(
260 0 : NSRectToSnappedRect(clipRect, appUnitsPerDevPixel, *drawTarget));
261 : result &=
262 : nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
263 : aDirtyRect, rect, mStyleContext,
264 0 : PaintBorderFlags::SYNC_DECODE_IMAGES, skipSides);
265 :
266 0 : aRenderingContext.Restore();
267 : } else {
268 : result &=
269 : nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
270 0 : aDirtyRect, nsRect(aPt, GetSize()),
271 : mStyleContext,
272 0 : PaintBorderFlags::SYNC_DECODE_IMAGES, skipSides);
273 : }
274 :
275 0 : return result;
276 : }
277 :
278 : nsIFrame*
279 0 : nsGroupBoxFrame::GetCaptionBox(nsRect& aCaptionRect)
280 : {
281 : // first child is our grouped area
282 0 : nsIFrame* box = nsBox::GetChildXULBox(this);
283 :
284 : // no area fail.
285 0 : if (!box)
286 0 : return nullptr;
287 :
288 : // get the first child in the grouped area, that is the caption
289 0 : box = nsBox::GetChildXULBox(box);
290 :
291 : // nothing in the area? fail
292 0 : if (!box)
293 0 : return nullptr;
294 :
295 : // now get the caption itself. It is in the caption frame.
296 0 : nsIFrame* child = nsBox::GetChildXULBox(box);
297 :
298 0 : if (child) {
299 : // convert to our coordinates.
300 0 : nsRect parentRect(box->GetRect());
301 0 : aCaptionRect = child->GetRect();
302 0 : aCaptionRect.x += parentRect.x;
303 0 : aCaptionRect.y += parentRect.y;
304 : }
305 :
306 0 : return child;
307 : }
308 :
309 : nsresult
310 0 : nsGroupBoxFrame::GetXULBorderAndPadding(nsMargin& aBorderAndPadding)
311 : {
312 0 : aBorderAndPadding.SizeTo(0,0,0,0);
313 0 : return NS_OK;
314 : }
315 :
|