Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/xul/nsDeckFrame.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
//
8
// Eric Vaughan
9
// Netscape Communications
10
//
11
// See documentation in associated header file
12
//
13
14
#include "nsDeckFrame.h"
15
#include "mozilla/ComputedStyle.h"
16
#include "nsPresContext.h"
17
#include "nsIContent.h"
18
#include "nsCOMPtr.h"
19
#include "nsNameSpaceManager.h"
20
#include "nsGkAtoms.h"
21
#include "nsHTMLParts.h"
22
#include "nsIPresShell.h"
23
#include "nsCSSRendering.h"
24
#include "nsViewManager.h"
25
#include "nsBoxLayoutState.h"
26
#include "nsStackLayout.h"
27
#include "nsDisplayList.h"
28
#include "nsContainerFrame.h"
29
#include "nsContentUtils.h"
30
#include "nsXULPopupManager.h"
31
32
#ifdef ACCESSIBILITY
33
#include "nsAccessibilityService.h"
34
#endif
35
36
nsIFrame*
37
NS_NewDeckFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle)
38
0
{
39
0
  return new (aPresShell) nsDeckFrame(aStyle);
40
0
}
41
42
NS_IMPL_FRAMEARENA_HELPERS(nsDeckFrame)
43
44
0
NS_QUERYFRAME_HEAD(nsDeckFrame)
45
0
  NS_QUERYFRAME_ENTRY(nsDeckFrame)
46
0
NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
47
48
nsDeckFrame::nsDeckFrame(ComputedStyle* aStyle)
49
  : nsBoxFrame(aStyle, kClassID)
50
  , mIndex(0)
51
0
{
52
0
  nsCOMPtr<nsBoxLayout> layout;
53
0
  NS_NewStackLayout(layout);
54
0
  SetXULLayoutManager(layout);
55
0
}
56
57
nsresult
58
nsDeckFrame::AttributeChanged(int32_t         aNameSpaceID,
59
                              nsAtom*        aAttribute,
60
                              int32_t         aModType)
61
0
{
62
0
  nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
63
0
                                             aModType);
64
0
65
0
66
0
   // if the index changed hide the old element and make the new element visible
67
0
  if (aAttribute == nsGkAtoms::selectedIndex) {
68
0
    IndexChanged();
69
0
  }
70
0
71
0
  return rv;
72
0
}
73
74
void
75
nsDeckFrame::Init(nsIContent*       aContent,
76
                  nsContainerFrame* aParent,
77
                  nsIFrame*         aPrevInFlow)
78
0
{
79
0
  nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
80
0
81
0
  mIndex = GetSelectedIndex();
82
0
}
83
84
void
85
nsDeckFrame::HideBox(nsIFrame* aBox)
86
0
{
87
0
  nsIPresShell::ClearMouseCapture(aBox);
88
0
}
89
90
void
91
nsDeckFrame::IndexChanged()
92
0
{
93
0
  //did the index change?
94
0
  int32_t index = GetSelectedIndex();
95
0
  if (index == mIndex)
96
0
    return;
97
0
98
0
  // redraw
99
0
  InvalidateFrame();
100
0
101
0
  // hide the currently showing box
102
0
  nsIFrame* currentBox = GetSelectedBox();
103
0
  if (currentBox) // only hide if it exists
104
0
    HideBox(currentBox);
105
0
106
0
  mIndex = index;
107
0
108
0
#ifdef ACCESSIBILITY
109
0
  nsAccessibilityService* accService = GetAccService();
110
0
  if (accService) {
111
0
    accService->DeckPanelSwitched(PresContext()->GetPresShell(), mContent,
112
0
                                  currentBox, GetSelectedBox());
113
0
  }
114
0
#endif
115
0
116
0
  // Force any popups that might be anchored on elements within hidden
117
0
  // box to update.
118
0
  nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
119
0
  if (pm && currentBox) {
120
0
    pm->UpdatePopupPositions(currentBox->PresContext()->RefreshDriver());
121
0
  }
122
0
}
123
124
int32_t
125
nsDeckFrame::GetSelectedIndex()
126
0
{
127
0
  // default index is 0
128
0
  int32_t index = 0;
129
0
130
0
  // get the index attribute
131
0
  nsAutoString value;
132
0
  if (mContent->AsElement()->GetAttr(kNameSpaceID_None,
133
0
                                     nsGkAtoms::selectedIndex, value)) {
134
0
    nsresult error;
135
0
136
0
    // convert it to an integer
137
0
    index = value.ToInteger(&error);
138
0
  }
139
0
140
0
  return index;
141
0
}
142
143
nsIFrame*
144
nsDeckFrame::GetSelectedBox()
145
0
{
146
0
  return (mIndex >= 0) ? mFrames.FrameAt(mIndex) : nullptr;
147
0
}
148
149
void
150
nsDeckFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
151
                              const nsDisplayListSet& aLists)
152
0
{
153
0
  // if a tab is hidden all its children are too.
154
0
  if (!StyleVisibility()->mVisible)
155
0
    return;
156
0
157
0
  nsBoxFrame::BuildDisplayList(aBuilder, aLists);
158
0
}
159
160
void
161
nsDeckFrame::RemoveFrame(ChildListID aListID,
162
                         nsIFrame* aOldFrame)
163
0
{
164
0
  nsIFrame* currentFrame = GetSelectedBox();
165
0
  if (currentFrame &&
166
0
      aOldFrame &&
167
0
      currentFrame != aOldFrame) {
168
0
    // If the frame we're removing is at an index that's less
169
0
    // than mIndex, that means we're going to be shifting indexes
170
0
    // by 1.
171
0
    //
172
0
    // We attempt to keep the same child displayed by automatically
173
0
    // updating our internal notion of the current index.
174
0
    int32_t removedIndex = mFrames.IndexOf(aOldFrame);
175
0
    MOZ_ASSERT(removedIndex >= 0,
176
0
               "A deck child was removed that was not in mFrames.");
177
0
    if (removedIndex < mIndex) {
178
0
      mIndex--;
179
0
      // This is going to cause us to handle the index change in IndexedChanged,
180
0
      // but since the new index will match mIndex, it's essentially a noop.
181
0
      nsContentUtils::AddScriptRunner(new nsSetAttrRunnable(
182
0
        mContent->AsElement(), nsGkAtoms::selectedIndex, mIndex));
183
0
    }
184
0
  }
185
0
  nsBoxFrame::RemoveFrame(aListID, aOldFrame);
186
0
}
187
188
void
189
nsDeckFrame::BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
190
                                         const nsDisplayListSet& aLists)
191
0
{
192
0
  // only paint the selected box
193
0
  nsIFrame* box = GetSelectedBox();
194
0
  if (!box)
195
0
    return;
196
0
197
0
  // Putting the child in the background list. This is a little weird but
198
0
  // it matches what we were doing before.
199
0
  nsDisplayListSet set(aLists, aLists.BlockBorderBackgrounds());
200
0
  BuildDisplayListForChild(aBuilder, box, set);
201
0
}
202
203
NS_IMETHODIMP
204
nsDeckFrame::DoXULLayout(nsBoxLayoutState& aState)
205
0
{
206
0
  // Make sure we tweak the state so it does not resize our children.
207
0
  // We will do that.
208
0
  uint32_t oldFlags = aState.LayoutFlags();
209
0
  aState.SetLayoutFlags(NS_FRAME_NO_SIZE_VIEW | NS_FRAME_NO_VISIBILITY);
210
0
211
0
  // do a normal layout
212
0
  nsresult rv = nsBoxFrame::DoXULLayout(aState);
213
0
214
0
  // run though each child. Hide all but the selected one
215
0
  nsIFrame* box = nsBox::GetChildXULBox(this);
216
0
217
0
  nscoord count = 0;
218
0
  while (box)
219
0
  {
220
0
    // make collapsed children not show up
221
0
    if (count != mIndex)
222
0
      HideBox(box);
223
0
224
0
    box = GetNextXULBox(box);
225
0
    count++;
226
0
  }
227
0
228
0
  aState.SetLayoutFlags(oldFlags);
229
0
230
0
  return rv;
231
0
}
232