Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/xul/nsGroupBoxFrame.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
// YY need to pass isMultiple before create called
8
9
#include "nsBoxFrame.h"
10
11
#include "gfxContext.h"
12
#include "mozilla/gfx/2D.h"
13
#include "nsCSSRendering.h"
14
#include "nsLayoutUtils.h"
15
#include "mozilla/ComputedStyle.h"
16
#include "nsDisplayList.h"
17
18
using namespace mozilla;
19
using namespace mozilla::gfx;
20
using namespace mozilla::image;
21
22
class nsGroupBoxFrame final : public nsBoxFrame
23
{
24
public:
25
  NS_DECL_FRAMEARENA_HELPERS(nsGroupBoxFrame)
26
27
  explicit nsGroupBoxFrame(ComputedStyle* aStyle):
28
0
    nsBoxFrame(aStyle, kClassID) {}
29
30
  virtual nsresult GetXULBorderAndPadding(nsMargin& aBorderAndPadding) override;
31
32
  virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
33
                                const nsDisplayListSet& aLists) override;
34
35
#ifdef DEBUG_FRAME_DUMP
36
  virtual nsresult GetFrameName(nsAString& aResult) const override {
37
    return MakeFrameName(NS_LITERAL_STRING("GroupBoxFrame"), aResult);
38
  }
39
#endif
40
41
0
  virtual bool HonorPrintBackgroundSettings() override { return false; }
42
43
  ImgDrawResult 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, ComputedStyle* aStyle):
64
      nsBoxFrame(aShell, aContext) {}
65
66
67
#ifdef DEBUG_FRAME_DUMP
68
  NS_IMETHOD GetFrameName(nsString& aResult) const override {
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
NS_NewGroupBoxFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
81
0
{
82
0
  return new (aPresShell) nsGroupBoxFrame(aStyle);
83
0
}
84
85
NS_IMPL_FRAMEARENA_HELPERS(nsGroupBoxFrame)
86
87
class nsDisplayXULGroupBorder final : public nsDisplayItem
88
{
89
public:
90
  nsDisplayXULGroupBorder(nsDisplayListBuilder* aBuilder,
91
                              nsGroupBoxFrame* aFrame) :
92
0
    nsDisplayItem(aBuilder, aFrame) {
93
0
    MOZ_COUNT_CTOR(nsDisplayXULGroupBorder);
94
0
  }
95
#ifdef NS_BUILD_REFCNT_LOGGING
96
  virtual ~nsDisplayXULGroupBorder() {
97
    MOZ_COUNT_DTOR(nsDisplayXULGroupBorder);
98
  }
99
#endif
100
101
  nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
102
  void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
103
                                 const nsDisplayItemGeometry* aGeometry,
104
                                 nsRegion *aInvalidRegion) const override;
105
  virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
106
0
                       HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override {
107
0
    aOutFrames->AppendElement(mFrame);
108
0
  }
109
  virtual void Paint(nsDisplayListBuilder* aBuilder,
110
                     gfxContext* aCtx) override;
111
  NS_DISPLAY_DECL_NAME("XULGroupBackground", TYPE_XUL_GROUP_BACKGROUND)
112
};
113
114
nsDisplayItemGeometry*
115
nsDisplayXULGroupBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder)
116
0
{
117
0
  return new nsDisplayItemGenericImageGeometry(this, aBuilder);
118
0
}
119
120
void
121
nsDisplayXULGroupBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
122
                                                   const nsDisplayItemGeometry* aGeometry,
123
                                                   nsRegion* aInvalidRegion) const
124
0
{
125
0
  auto geometry =
126
0
    static_cast<const nsDisplayItemGenericImageGeometry*>(aGeometry);
127
0
128
0
  if (aBuilder->ShouldSyncDecodeImages() &&
129
0
      geometry->ShouldInvalidateToSyncDecodeImages()) {
130
0
    bool snap;
131
0
    aInvalidRegion->Or(*aInvalidRegion, GetBounds(aBuilder, &snap));
132
0
  }
133
0
134
0
  nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
135
0
}
136
137
void
138
nsDisplayXULGroupBorder::Paint(nsDisplayListBuilder* aBuilder,
139
                                   gfxContext* aCtx)
140
0
{
141
0
  ImgDrawResult result = static_cast<nsGroupBoxFrame*>(mFrame)
142
0
    ->PaintBorder(*aCtx, ToReferenceFrame(), GetPaintRect());
143
0
144
0
  nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
145
0
}
146
147
void
148
nsGroupBoxFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
149
                                  const nsDisplayListSet& aLists)
150
0
{
151
0
  // Paint our background and border
152
0
  if (IsVisibleForPainting(aBuilder)) {
153
0
    nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
154
0
      aBuilder, this, GetBackgroundRectRelativeToSelf(),
155
0
      aLists.BorderBackground());
156
0
    aLists.BorderBackground()->AppendToTop(
157
0
      MakeDisplayItem<nsDisplayXULGroupBorder>(aBuilder, this));
158
0
159
0
    DisplayOutline(aBuilder, aLists);
160
0
  }
161
0
162
0
  BuildDisplayListForChildren(aBuilder, aLists);
163
0
}
164
165
nsRect
166
nsGroupBoxFrame::GetBackgroundRectRelativeToSelf(nscoord* aOutYOffset, nsRect* aOutGroupRect)
167
0
{
168
0
  const nsMargin& border = StyleBorder()->GetComputedBorder();
169
0
170
0
  nsRect groupRect;
171
0
  nsIFrame* groupBox = GetCaptionBox(groupRect);
172
0
173
0
  nscoord yoff = 0;
174
0
  if (groupBox) {
175
0
    // If the border is smaller than the legend, move the border down
176
0
    // to be centered on the legend.
177
0
    nsMargin groupMargin;
178
0
    groupBox->StyleMargin()->GetMargin(groupMargin);
179
0
    groupRect.Inflate(groupMargin);
180
0
181
0
    if (border.top < groupRect.height) {
182
0
      yoff = (groupRect.height - border.top) / 2 + groupRect.y;
183
0
    }
184
0
  }
185
0
186
0
  if (aOutYOffset) {
187
0
    *aOutYOffset = yoff;
188
0
  }
189
0
  if (aOutGroupRect) {
190
0
    *aOutGroupRect = groupRect;
191
0
  }
192
0
193
0
  return nsRect(0, yoff, mRect.width, mRect.height - yoff);
194
0
}
195
196
ImgDrawResult
197
nsGroupBoxFrame::PaintBorder(gfxContext& aRenderingContext,
198
0
    nsPoint aPt, const nsRect& aDirtyRect) {
199
0
200
0
  DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
201
0
202
0
  Sides skipSides;
203
0
  const nsStyleBorder* borderStyleData = StyleBorder();
204
0
  const nsMargin& border = borderStyleData->GetComputedBorder();
205
0
  nsPresContext* presContext = PresContext();
206
0
207
0
  nsRect groupRect;
208
0
  nsIFrame* groupBox = GetCaptionBox(groupRect);
209
0
210
0
  nscoord yoff = 0;
211
0
  nsRect rect = GetBackgroundRectRelativeToSelf(&yoff, &groupRect) + aPt;
212
0
  groupRect += aPt;
213
0
214
0
  ImgDrawResult result = ImgDrawResult::SUCCESS;
215
0
  if (groupBox) {
216
0
    int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
217
0
218
0
    // we should probably use PaintBorderEdges to do this but for now just use clipping
219
0
    // to achieve the same effect.
220
0
221
0
    // draw left side
222
0
    nsRect clipRect(rect);
223
0
    clipRect.width = groupRect.x - rect.x;
224
0
    clipRect.height = border.top;
225
0
226
0
    aRenderingContext.Save();
227
0
    aRenderingContext.Clip(
228
0
      NSRectToSnappedRect(clipRect, appUnitsPerDevPixel, *drawTarget));
229
0
    result &=
230
0
      nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
231
0
                                  aDirtyRect, rect, mComputedStyle,
232
0
                                  PaintBorderFlags::SYNC_DECODE_IMAGES, skipSides);
233
0
    aRenderingContext.Restore();
234
0
235
0
    // draw right side
236
0
    clipRect = rect;
237
0
    clipRect.x = groupRect.XMost();
238
0
    clipRect.width = rect.XMost() - groupRect.XMost();
239
0
    clipRect.height = border.top;
240
0
241
0
    aRenderingContext.Save();
242
0
    aRenderingContext.Clip(
243
0
      NSRectToSnappedRect(clipRect, appUnitsPerDevPixel, *drawTarget));
244
0
    result &=
245
0
      nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
246
0
                                  aDirtyRect, rect, mComputedStyle,
247
0
                                  PaintBorderFlags::SYNC_DECODE_IMAGES, skipSides);
248
0
249
0
    aRenderingContext.Restore();
250
0
    // draw bottom
251
0
252
0
    clipRect = rect;
253
0
    clipRect.y += border.top;
254
0
    clipRect.height = mRect.height - (yoff + border.top);
255
0
256
0
    aRenderingContext.Save();
257
0
    aRenderingContext.Clip(
258
0
      NSRectToSnappedRect(clipRect, appUnitsPerDevPixel, *drawTarget));
259
0
    result &=
260
0
      nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
261
0
                                  aDirtyRect, rect, mComputedStyle,
262
0
                                  PaintBorderFlags::SYNC_DECODE_IMAGES, skipSides);
263
0
264
0
    aRenderingContext.Restore();
265
0
  } else {
266
0
    result &=
267
0
      nsCSSRendering::PaintBorder(presContext, aRenderingContext, this,
268
0
                                  aDirtyRect, nsRect(aPt, GetSize()),
269
0
                                  mComputedStyle,
270
0
                                  PaintBorderFlags::SYNC_DECODE_IMAGES, skipSides);
271
0
  }
272
0
273
0
  return result;
274
0
}
275
276
nsIFrame*
277
nsGroupBoxFrame::GetCaptionBox(nsRect& aCaptionRect)
278
0
{
279
0
    // first child is our grouped area
280
0
    nsIFrame* box = nsBox::GetChildXULBox(this);
281
0
282
0
    // no area fail.
283
0
    if (!box)
284
0
      return nullptr;
285
0
286
0
    // get the first child in the grouped area, that is the caption
287
0
    box = nsBox::GetChildXULBox(box);
288
0
289
0
    // nothing in the area? fail
290
0
    if (!box)
291
0
      return nullptr;
292
0
293
0
    // now get the caption itself. It is in the caption frame.
294
0
    nsIFrame* child = nsBox::GetChildXULBox(box);
295
0
296
0
    if (child) {
297
0
       // convert to our coordinates.
298
0
       nsRect parentRect(box->GetRect());
299
0
       aCaptionRect = child->GetRect();
300
0
       aCaptionRect.x += parentRect.x;
301
0
       aCaptionRect.y += parentRect.y;
302
0
    }
303
0
304
0
    return child;
305
0
}
306
307
nsresult
308
nsGroupBoxFrame::GetXULBorderAndPadding(nsMargin& aBorderAndPadding)
309
0
{
310
0
  aBorderAndPadding.SizeTo(0,0,0,0);
311
0
  return NS_OK;
312
0
}
313