Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/xul/nsRootBoxFrame.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
#include "nsHTMLParts.h"
8
#include "nsStyleConsts.h"
9
#include "nsGkAtoms.h"
10
#include "nsIPresShell.h"
11
#include "nsBoxFrame.h"
12
#include "nsDisplayList.h"
13
#include "nsStackLayout.h"
14
#include "nsIPopupContainer.h"
15
#include "nsIContent.h"
16
#include "nsFrameManager.h"
17
#include "mozilla/BasicEvents.h"
18
19
using namespace mozilla;
20
21
// Interface IDs
22
23
//#define DEBUG_REFLOW
24
25
// static
26
nsIPopupContainer*
27
nsIPopupContainer::GetPopupContainer(nsIPresShell* aShell)
28
0
{
29
0
  if (!aShell) {
30
0
    return nullptr;
31
0
  }
32
0
  nsIFrame* rootFrame = aShell->GetRootFrame();
33
0
  if (!rootFrame) {
34
0
    return nullptr;
35
0
  }
36
0
37
0
  if (rootFrame) {
38
0
    rootFrame = rootFrame->PrincipalChildList().FirstChild();
39
0
  }
40
0
41
0
  nsIPopupContainer* rootBox = do_QueryFrame(rootFrame);
42
0
43
0
  // If the rootBox was not found yet this may be a top level non-XUL document.
44
0
  if (rootFrame && !rootBox) {
45
0
    // In a non-XUL document the rootFrame here will be a nsHTMLScrollFrame,
46
0
    // get the nsCanvasFrame (which is the popup container) from it.
47
0
    rootFrame = rootFrame->GetContentInsertionFrame();
48
0
    rootBox = do_QueryFrame(rootFrame);
49
0
  }
50
0
51
0
  return rootBox;
52
0
}
53
54
class nsRootBoxFrame final : public nsBoxFrame, public nsIPopupContainer
55
{
56
public:
57
58
  friend nsIFrame* NS_NewBoxFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
59
60
  explicit nsRootBoxFrame(ComputedStyle* aStyle);
61
62
  NS_DECL_QUERYFRAME
63
  NS_DECL_FRAMEARENA_HELPERS(nsRootBoxFrame)
64
65
  virtual nsPopupSetFrame* GetPopupSetFrame() override;
66
  virtual void SetPopupSetFrame(nsPopupSetFrame* aPopupSet) override;
67
  virtual Element* GetDefaultTooltip() override;
68
  virtual void SetDefaultTooltip(Element* aTooltip) override;
69
70
  virtual void AppendFrames(ChildListID     aListID,
71
                            nsFrameList&    aFrameList) override;
72
  virtual void InsertFrames(ChildListID     aListID,
73
                            nsIFrame*       aPrevFrame,
74
                            nsFrameList&    aFrameList) override;
75
  virtual void RemoveFrame(ChildListID     aListID,
76
                           nsIFrame*       aOldFrame) override;
77
78
  virtual void Reflow(nsPresContext*          aPresContext,
79
                          ReflowOutput&     aDesiredSize,
80
                          const ReflowInput& aReflowInput,
81
                          nsReflowStatus&          aStatus) override;
82
  virtual nsresult HandleEvent(nsPresContext* aPresContext,
83
                               WidgetGUIEvent* aEvent,
84
                               nsEventStatus* aEventStatus) override;
85
86
  virtual void BuildDisplayList(nsDisplayListBuilder*   aBuilder,
87
                                const nsDisplayListSet& aLists) override;
88
89
  virtual bool IsFrameOfType(uint32_t aFlags) const override
90
0
  {
91
0
    // Override bogus IsFrameOfType in nsBoxFrame.
92
0
    if (aFlags & (nsIFrame::eReplacedContainsBlock | nsIFrame::eReplaced))
93
0
      return false;
94
0
    return nsBoxFrame::IsFrameOfType(aFlags);
95
0
  }
96
97
#ifdef DEBUG_FRAME_DUMP
98
  virtual nsresult GetFrameName(nsAString& aResult) const override;
99
#endif
100
101
  nsPopupSetFrame* mPopupSetFrame;
102
103
protected:
104
  Element* mDefaultTooltip;
105
};
106
107
//----------------------------------------------------------------------
108
109
nsContainerFrame*
110
NS_NewRootBoxFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
111
0
{
112
0
  return new (aPresShell) nsRootBoxFrame(aStyle);
113
0
}
114
115
NS_IMPL_FRAMEARENA_HELPERS(nsRootBoxFrame)
116
117
nsRootBoxFrame::nsRootBoxFrame(ComputedStyle* aStyle)
118
  : nsBoxFrame(aStyle, kClassID, true)
119
  , mPopupSetFrame(nullptr)
120
  , mDefaultTooltip(nullptr)
121
0
{
122
0
  nsCOMPtr<nsBoxLayout> layout;
123
0
  NS_NewStackLayout(layout);
124
0
  SetXULLayoutManager(layout);
125
0
}
126
127
void
128
nsRootBoxFrame::AppendFrames(ChildListID     aListID,
129
                             nsFrameList&    aFrameList)
130
0
{
131
0
  MOZ_ASSERT(aListID == kPrincipalList, "unexpected child list ID");
132
0
  MOZ_ASSERT(mFrames.IsEmpty(), "already have a child frame");
133
0
  nsBoxFrame::AppendFrames(aListID, aFrameList);
134
0
}
135
136
void
137
nsRootBoxFrame::InsertFrames(ChildListID     aListID,
138
                             nsIFrame*       aPrevFrame,
139
                             nsFrameList&    aFrameList)
140
0
{
141
0
  // Because we only support a single child frame inserting is the same
142
0
  // as appending.
143
0
  MOZ_ASSERT(!aPrevFrame, "unexpected previous sibling frame");
144
0
  AppendFrames(aListID, aFrameList);
145
0
}
146
147
void
148
nsRootBoxFrame::RemoveFrame(ChildListID     aListID,
149
                            nsIFrame*       aOldFrame)
150
0
{
151
0
  NS_ASSERTION(aListID == kPrincipalList, "unexpected child list ID");
152
0
  if (aOldFrame == mFrames.FirstChild()) {
153
0
    nsBoxFrame::RemoveFrame(aListID, aOldFrame);
154
0
  } else {
155
0
    MOZ_CRASH("unknown aOldFrame");
156
0
  }
157
0
}
158
159
#ifdef DEBUG_REFLOW
160
int32_t gReflows = 0;
161
#endif
162
163
void
164
nsRootBoxFrame::Reflow(nsPresContext*           aPresContext,
165
                       ReflowOutput&     aDesiredSize,
166
                       const ReflowInput& aReflowInput,
167
                       nsReflowStatus&          aStatus)
168
0
{
169
0
  DO_GLOBAL_REFLOW_COUNT("nsRootBoxFrame");
170
0
  MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
171
0
172
#ifdef DEBUG_REFLOW
173
  gReflows++;
174
  printf("----Reflow %d----\n", gReflows);
175
#endif
176
  return nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
177
0
}
178
179
void
180
nsRootBoxFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
181
                                 const nsDisplayListSet& aLists)
182
0
{
183
0
  if (mContent && mContent->GetProperty(nsGkAtoms::DisplayPortMargins)) {
184
0
    // The XUL document's root element may have displayport margins set in
185
0
    // ChromeProcessController::InitializeRoot, and we should to supply the
186
0
    // base rect.
187
0
    nsRect displayPortBase =
188
0
      aBuilder->GetVisibleRect().Intersect(nsRect(nsPoint(0, 0), GetSize()));
189
0
    nsLayoutUtils::SetDisplayPortBase(mContent, displayPortBase);
190
0
  }
191
0
192
0
  // root boxes don't need a debug border/outline or a selection overlay...
193
0
  // They *may* have a background propagated to them, so force creation
194
0
  // of a background display list element.
195
0
  DisplayBorderBackgroundOutline(aBuilder, aLists, true);
196
0
197
0
  BuildDisplayListForChildren(aBuilder, aLists);
198
0
}
199
200
nsresult
201
nsRootBoxFrame::HandleEvent(nsPresContext* aPresContext,
202
                            WidgetGUIEvent* aEvent,
203
                            nsEventStatus* aEventStatus)
204
0
{
205
0
  NS_ENSURE_ARG_POINTER(aEventStatus);
206
0
  if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
207
0
    return NS_OK;
208
0
  }
209
0
210
0
  if (aEvent->mMessage == eMouseUp) {
211
0
    nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
212
0
  }
213
0
214
0
  return NS_OK;
215
0
}
216
217
nsPopupSetFrame*
218
nsRootBoxFrame::GetPopupSetFrame()
219
0
{
220
0
  return mPopupSetFrame;
221
0
}
222
223
void
224
nsRootBoxFrame::SetPopupSetFrame(nsPopupSetFrame* aPopupSet)
225
0
{
226
0
  // Under normal conditions this should only be called once.  However,
227
0
  // if something triggers ReconstructDocElementHierarchy, we will
228
0
  // destroy this frame's child (the nsDocElementBoxFrame), but not this
229
0
  // frame.  This will cause the popupset to remove itself by calling
230
0
  // |SetPopupSetFrame(nullptr)|, and then we'll be able to accept a new
231
0
  // popupset.  Since the anonymous content is associated with the
232
0
  // nsDocElementBoxFrame, we'll get a new popupset when the new doc
233
0
  // element box frame is created.
234
0
  MOZ_ASSERT(!aPopupSet || !mPopupSetFrame,
235
0
             "Popup set is already defined! Only 1 allowed.");
236
0
  mPopupSetFrame = aPopupSet;
237
0
}
238
239
Element*
240
nsRootBoxFrame::GetDefaultTooltip()
241
0
{
242
0
  return mDefaultTooltip;
243
0
}
244
245
void
246
nsRootBoxFrame::SetDefaultTooltip(Element* aTooltip)
247
0
{
248
0
  mDefaultTooltip = aTooltip;
249
0
}
250
251
0
NS_QUERYFRAME_HEAD(nsRootBoxFrame)
252
0
  NS_QUERYFRAME_ENTRY(nsIPopupContainer)
253
0
NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
254
255
#ifdef DEBUG_FRAME_DUMP
256
nsresult
257
nsRootBoxFrame::GetFrameName(nsAString& aResult) const
258
{
259
  return MakeFrameName(NS_LITERAL_STRING("RootBox"), aResult);
260
}
261
#endif