Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/xul/nsButtonBoxFrame.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
#include "nsCOMPtr.h"
7
#include "nsButtonBoxFrame.h"
8
#include "nsIContent.h"
9
#include "nsIDOMXULButtonElement.h"
10
#include "nsGkAtoms.h"
11
#include "nsNameSpaceManager.h"
12
#include "nsPresContext.h"
13
#include "nsIPresShell.h"
14
#include "nsDisplayList.h"
15
#include "nsContentUtils.h"
16
#include "mozilla/dom/Element.h"
17
#include "mozilla/dom/Event.h"
18
#include "mozilla/dom/MouseEventBinding.h"
19
#include "mozilla/EventStateManager.h"
20
#include "mozilla/EventStates.h"
21
#include "mozilla/MouseEvents.h"
22
#include "mozilla/TextEvents.h"
23
24
using namespace mozilla;
25
26
27
NS_IMPL_ISUPPORTS(nsButtonBoxFrame::nsButtonBoxListener, nsIDOMEventListener)
28
29
nsresult
30
nsButtonBoxFrame::nsButtonBoxListener::HandleEvent(dom::Event* aEvent)
31
0
{
32
0
  if (!mButtonBoxFrame) {
33
0
    return NS_OK;
34
0
  }
35
0
36
0
  nsAutoString eventType;
37
0
  aEvent->GetType(eventType);
38
0
39
0
  if (eventType.EqualsLiteral("blur")) {
40
0
    mButtonBoxFrame->Blurred();
41
0
    return NS_OK;
42
0
  }
43
0
44
0
  MOZ_ASSERT_UNREACHABLE("Unexpected eventType");
45
0
  return NS_OK;
46
0
}
47
48
//
49
// NS_NewXULButtonFrame
50
//
51
// Creates a new Button frame and returns it
52
//
53
nsIFrame*
54
NS_NewButtonBoxFrame (nsIPresShell* aPresShell, ComputedStyle* aStyle)
55
0
{
56
0
  return new (aPresShell) nsButtonBoxFrame(aStyle);
57
0
}
58
59
NS_IMPL_FRAMEARENA_HELPERS(nsButtonBoxFrame)
60
61
nsButtonBoxFrame::nsButtonBoxFrame(ComputedStyle* aStyle, ClassID aID) :
62
  nsBoxFrame(aStyle, aID, false),
63
  mButtonBoxListener(nullptr),
64
  mIsHandlingKeyEvent(false)
65
0
{
66
0
  UpdateMouseThrough();
67
0
}
68
69
void
70
nsButtonBoxFrame::Init(nsIContent*       aContent,
71
                       nsContainerFrame* aParent,
72
                       nsIFrame*         aPrevInFlow)
73
0
{
74
0
  nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
75
0
76
0
  mButtonBoxListener = new nsButtonBoxListener(this);
77
0
78
0
  mContent->AddSystemEventListener(NS_LITERAL_STRING("blur"), mButtonBoxListener, false);
79
0
}
80
81
void
82
nsButtonBoxFrame::DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData)
83
0
{
84
0
  mContent->RemoveSystemEventListener(NS_LITERAL_STRING("blur"), mButtonBoxListener, false);
85
0
86
0
  mButtonBoxListener->mButtonBoxFrame = nullptr;
87
0
  mButtonBoxListener = nullptr;
88
0
89
0
  nsBoxFrame::DestroyFrom(aDestructRoot, aPostDestroyData);
90
0
}
91
92
void
93
nsButtonBoxFrame::BuildDisplayListForChildren(nsDisplayListBuilder*   aBuilder,
94
                                              const nsDisplayListSet& aLists)
95
0
{
96
0
  // override, since we don't want children to get events
97
0
  if (aBuilder->IsForEventDelivery())
98
0
    return;
99
0
  nsBoxFrame::BuildDisplayListForChildren(aBuilder, aLists);
100
0
}
101
102
nsresult
103
nsButtonBoxFrame::HandleEvent(nsPresContext* aPresContext,
104
                              WidgetGUIEvent* aEvent,
105
                              nsEventStatus* aEventStatus)
106
0
{
107
0
  NS_ENSURE_ARG_POINTER(aEventStatus);
108
0
  if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
109
0
    return NS_OK;
110
0
  }
111
0
112
0
  switch (aEvent->mMessage) {
113
0
    case eKeyDown: {
114
0
      WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
115
0
      if (!keyEvent) {
116
0
        break;
117
0
      }
118
0
      if (NS_VK_SPACE == keyEvent->mKeyCode) {
119
0
        EventStateManager* esm = aPresContext->EventStateManager();
120
0
        // :hover:active state
121
0
        esm->SetContentState(mContent, NS_EVENT_STATE_HOVER);
122
0
        esm->SetContentState(mContent, NS_EVENT_STATE_ACTIVE);
123
0
        mIsHandlingKeyEvent = true;
124
0
      }
125
0
      break;
126
0
    }
127
0
128
0
// On mac, Return fires the default button, not the focused one.
129
0
#ifndef XP_MACOSX
130
0
    case eKeyPress: {
131
0
      WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
132
0
      if (!keyEvent) {
133
0
        break;
134
0
      }
135
0
      if (NS_VK_RETURN == keyEvent->mKeyCode) {
136
0
        nsCOMPtr<nsIDOMXULButtonElement> buttonEl(do_QueryInterface(mContent));
137
0
        if (buttonEl) {
138
0
          MouseClicked(aEvent);
139
0
          *aEventStatus = nsEventStatus_eConsumeNoDefault;
140
0
        }
141
0
      }
142
0
      break;
143
0
    }
144
0
#endif
145
0
146
0
    case eKeyUp: {
147
0
      WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
148
0
      if (!keyEvent) {
149
0
        break;
150
0
      }
151
0
      if (NS_VK_SPACE == keyEvent->mKeyCode) {
152
0
        mIsHandlingKeyEvent = false;
153
0
        // only activate on keyup if we're already in the :hover:active state
154
0
        NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?");
155
0
        EventStates buttonState = mContent->AsElement()->State();
156
0
        if (buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE |
157
0
                                     NS_EVENT_STATE_HOVER)) {
158
0
          // return to normal state
159
0
          EventStateManager* esm = aPresContext->EventStateManager();
160
0
          esm->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
161
0
          esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER);
162
0
          MouseClicked(aEvent);
163
0
        }
164
0
      }
165
0
      break;
166
0
    }
167
0
168
0
    case eMouseClick: {
169
0
      WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
170
0
      if (mouseEvent->IsLeftClickEvent()) {
171
0
        MouseClicked(mouseEvent);
172
0
      }
173
0
      break;
174
0
    }
175
0
176
0
    default:
177
0
      break;
178
0
  }
179
0
180
0
  return nsBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
181
0
}
182
183
void
184
nsButtonBoxFrame::Blurred()
185
0
{
186
0
  NS_ASSERTION(mContent->IsElement(), "How do we have a non-element?");
187
0
  EventStates buttonState = mContent->AsElement()->State();
188
0
  if (mIsHandlingKeyEvent &&
189
0
      buttonState.HasAllStates(NS_EVENT_STATE_ACTIVE |
190
0
                               NS_EVENT_STATE_HOVER)) {
191
0
    // return to normal state
192
0
    EventStateManager* esm = PresContext()->EventStateManager();
193
0
    esm->SetContentState(nullptr, NS_EVENT_STATE_ACTIVE);
194
0
    esm->SetContentState(nullptr, NS_EVENT_STATE_HOVER);
195
0
  }
196
0
  mIsHandlingKeyEvent = false;
197
0
}
198
199
void
200
nsButtonBoxFrame::MouseClicked(WidgetGUIEvent* aEvent)
201
0
{
202
0
  // Don't execute if we're disabled.
203
0
  if (mContent->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::disabled,
204
0
                                         nsGkAtoms::_true, eCaseMatters))
205
0
    return;
206
0
207
0
  // Have the content handle the event, propagating it according to normal DOM rules.
208
0
  nsCOMPtr<nsIPresShell> shell = PresContext()->GetPresShell();
209
0
  if (!shell)
210
0
    return;
211
0
212
0
  // Execute the oncommand event handler.
213
0
  WidgetInputEvent* inputEvent = aEvent->AsInputEvent();
214
0
  WidgetMouseEventBase* mouseEvent = aEvent->AsMouseEventBase();
215
0
  nsContentUtils::DispatchXULCommand(mContent, aEvent->IsTrusted(), nullptr,
216
0
                                     shell, inputEvent->IsControl(),
217
0
                                     inputEvent->IsAlt(), inputEvent->IsShift(),
218
0
                                     inputEvent->IsMeta(),
219
0
                                     mouseEvent ? mouseEvent->inputSource
220
0
                                                : MouseEvent_Binding::MOZ_SOURCE_UNKNOWN);
221
0
}