1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "base/basictypes.h"
10 #include "BasicLayers.h"
11 #include "gfxPlatform.h"
12 #if defined(MOZ_ENABLE_D3D10_LAYER)
13 # include "LayerManagerD3D10.h"
15 #include "mozilla/dom/TabChild.h"
16 #include "mozilla/Hal.h"
17 #include "mozilla/layers/CompositorChild.h"
18 #include "mozilla/layers/PLayersChild.h"
19 #include "PuppetWidget.h"
20 #include "nsIWidgetListener.h"
22 using namespace mozilla::dom
;
23 using namespace mozilla::hal
;
24 using namespace mozilla::layers
;
25 using namespace mozilla::widget
;
28 InvalidateRegion(nsIWidget
* aWidget
, const nsIntRegion
& aRegion
)
30 nsIntRegionRectIterator
it(aRegion
);
31 while(const nsIntRect
* r
= it
.Next()) {
32 aWidget
->Invalidate(*r
);
36 /*static*/ already_AddRefed
<nsIWidget
>
37 nsIWidget::CreatePuppetWidget(TabChild
* aTabChild
)
39 NS_ABORT_IF_FALSE(nsIWidget::UsePuppetWidgets(),
40 "PuppetWidgets not allowed in this configuration");
42 nsCOMPtr
<nsIWidget
> widget
= new PuppetWidget(aTabChild
);
43 return widget
.forget();
50 IsPopup(const nsWidgetInitData
* aInitData
)
52 return aInitData
&& aInitData
->mWindowType
== eWindowType_popup
;
56 MightNeedIMEFocus(const nsWidgetInitData
* aInitData
)
58 // In the puppet-widget world, popup widgets are just dummies and
59 // shouldn't try to mess with IME state.
60 return !IsPopup(aInitData
);
64 // Arbitrary, fungible.
65 const size_t PuppetWidget::kMaxDimension
= 4000;
67 NS_IMPL_ISUPPORTS_INHERITED1(PuppetWidget
, nsBaseWidget
,
68 nsISupportsWeakReference
)
70 PuppetWidget::PuppetWidget(TabChild
* aTabChild
)
71 : mTabChild(aTabChild
)
74 MOZ_COUNT_CTOR(PuppetWidget
);
77 PuppetWidget::~PuppetWidget()
79 MOZ_COUNT_DTOR(PuppetWidget
);
83 PuppetWidget::Create(nsIWidget
*aParent
,
84 nsNativeWidget aNativeParent
,
85 const nsIntRect
&aRect
,
86 nsDeviceContext
*aContext
,
87 nsWidgetInitData
*aInitData
)
89 NS_ABORT_IF_FALSE(!aNativeParent
, "got a non-Puppet native parent");
91 BaseCreate(nullptr, aRect
, aContext
, aInitData
);
97 mSurface
= gfxPlatform::GetPlatform()
98 ->CreateOffscreenSurface(gfxIntSize(1, 1),
99 gfxASurface::ContentFromFormat(gfxASurface::ImageFormatARGB32
));
101 mIMEComposing
= false;
102 mNeedIMEStateInit
= MightNeedIMEFocus(aInitData
);
104 PuppetWidget
* parent
= static_cast<PuppetWidget
*>(aParent
);
106 parent
->SetChild(this);
107 mLayerManager
= parent
->GetLayerManager();
110 Resize(mBounds
.x
, mBounds
.y
, mBounds
.width
, mBounds
.height
, false);
117 PuppetWidget::InitIMEState()
119 if (mNeedIMEStateInit
) {
120 uint32_t chromeSeqno
;
121 mTabChild
->SendNotifyIMEFocus(false, &mIMEPreference
, &chromeSeqno
);
122 mIMELastBlurSeqno
= mIMELastReceivedSeqno
= chromeSeqno
;
123 mNeedIMEStateInit
= false;
127 already_AddRefed
<nsIWidget
>
128 PuppetWidget::CreateChild(const nsIntRect
&aRect
,
129 nsDeviceContext
*aContext
,
130 nsWidgetInitData
*aInitData
,
131 bool aForceUseIWidgetParent
)
133 bool isPopup
= IsPopup(aInitData
);
134 nsCOMPtr
<nsIWidget
> widget
= nsIWidget::CreatePuppetWidget(mTabChild
);
136 NS_SUCCEEDED(widget
->Create(isPopup
? nullptr: this, nullptr, aRect
,
137 aContext
, aInitData
))) ?
138 widget
.forget() : nullptr);
142 PuppetWidget::Destroy()
149 mLayerManager
->Destroy();
151 mLayerManager
= nullptr;
157 PuppetWidget::Show(bool aState
)
159 NS_ASSERTION(mEnabled
,
160 "does it make sense to Show()/Hide() a disabled widget?");
162 bool wasVisible
= mVisible
;
166 mChild
->mVisible
= aState
;
169 if (!mVisible
&& mLayerManager
) {
170 mLayerManager
->ClearCachedResources();
173 if (!wasVisible
&& mVisible
) {
174 Resize(mBounds
.width
, mBounds
.height
, false);
182 PuppetWidget::Resize(int32_t aWidth
,
186 nsIntRect oldBounds
= mBounds
;
187 mBounds
.SizeTo(nsIntSize(aWidth
, aHeight
));
190 return mChild
->Resize(aWidth
, aHeight
, aRepaint
);
193 // XXX: roc says that |aRepaint| dictates whether or not to
194 // invalidate the expanded area
195 if (oldBounds
.Size() < mBounds
.Size() && aRepaint
) {
196 nsIntRegion
dirty(mBounds
);
197 dirty
.Sub(dirty
, oldBounds
);
198 InvalidateRegion(this, dirty
);
201 if (!oldBounds
.IsEqualEdges(mBounds
) && mAttachedWidgetListener
) {
202 mAttachedWidgetListener
->WindowResized(this, mBounds
.width
, mBounds
.height
);
209 PuppetWidget::SetFocus(bool aRaise
)
211 // XXX/cjones: someone who knows about event handling needs to
212 // decide how this should work.
217 PuppetWidget::Invalidate(const nsIntRect
& aRect
)
220 debug_DumpInvalidate(stderr
, this, &aRect
,
221 nsAutoCString("PuppetWidget"), 0);
225 return mChild
->Invalidate(aRect
);
228 mDirtyRegion
.Or(mDirtyRegion
, aRect
);
230 if (!mDirtyRegion
.IsEmpty() && !mPaintTask
.IsPending()) {
231 mPaintTask
= new PaintTask(this);
232 return NS_DispatchToCurrentThread(mPaintTask
.get());
239 PuppetWidget::InitEvent(nsGUIEvent
& event
, nsIntPoint
* aPoint
)
241 if (nullptr == aPoint
) {
242 event
.refPoint
.x
= 0;
243 event
.refPoint
.y
= 0;
246 // use the point override if provided
247 event
.refPoint
.x
= aPoint
->x
;
248 event
.refPoint
.y
= aPoint
->y
;
250 event
.time
= PR_Now() / 1000;
254 PuppetWidget::DispatchEvent(nsGUIEvent
* event
, nsEventStatus
& aStatus
)
257 debug_DumpEvent(stdout
, event
->widget
, event
,
258 nsAutoCString("PuppetWidget"), 0);
261 NS_ABORT_IF_FALSE(!mChild
|| mChild
->mWindowType
== eWindowType_popup
,
262 "Unexpected event dispatch!");
264 aStatus
= nsEventStatus_eIgnore
;
266 if (event
->message
== NS_COMPOSITION_START
) {
267 mIMEComposing
= true;
269 switch (event
->eventStructType
) {
270 case NS_COMPOSITION_EVENT
:
271 mIMELastReceivedSeqno
= static_cast<nsCompositionEvent
*>(event
)->seqno
;
272 if (mIMELastReceivedSeqno
< mIMELastBlurSeqno
)
276 mIMELastReceivedSeqno
= static_cast<nsTextEvent
*>(event
)->seqno
;
277 if (mIMELastReceivedSeqno
< mIMELastBlurSeqno
)
280 case NS_SELECTION_EVENT
:
281 mIMELastReceivedSeqno
= static_cast<nsSelectionEvent
*>(event
)->seqno
;
282 if (mIMELastReceivedSeqno
< mIMELastBlurSeqno
)
287 if (mAttachedWidgetListener
) {
288 aStatus
= mAttachedWidgetListener
->HandleEvent(event
, mUseAttachedEvents
);
291 if (event
->message
== NS_COMPOSITION_END
) {
292 mIMEComposing
= false;
299 PuppetWidget::GetLayerManager(PLayersChild
* aShadowManager
,
300 LayersBackend aBackendHint
,
301 LayerManagerPersistence aPersistence
,
302 bool* aAllowRetaining
)
304 if (!mLayerManager
) {
305 // The backend hint is a temporary placeholder until Azure, when
306 // all content-process layer managers will be BasicLayerManagers.
307 #if defined(MOZ_ENABLE_D3D10_LAYER)
308 if (mozilla::layers::LAYERS_D3D10
== aBackendHint
) {
309 nsRefPtr
<LayerManagerD3D10
> m
= new LayerManagerD3D10(this);
310 m
->AsShadowForwarder()->SetShadowManager(aShadowManager
);
311 if (m
->Initialize()) {
316 if (!mLayerManager
) {
317 mLayerManager
= new BasicShadowLayerManager(this);
318 mLayerManager
->AsShadowForwarder()->SetShadowManager(aShadowManager
);
321 if (aAllowRetaining
) {
322 *aAllowRetaining
= true;
324 return mLayerManager
;
328 PuppetWidget::GetThebesSurface()
334 PuppetWidget::IMEEndComposition(bool aCancel
)
336 nsEventStatus status
;
337 nsTextEvent
textEvent(true, NS_TEXT_TEXT
, this);
338 InitEvent(textEvent
, nullptr);
339 textEvent
.seqno
= mIMELastReceivedSeqno
;
340 // SendEndIMEComposition is always called since ResetInputState
341 // should always be called even if we aren't composing something.
343 !mTabChild
->SendEndIMEComposition(aCancel
, &textEvent
.theText
)) {
344 return NS_ERROR_FAILURE
;
350 DispatchEvent(&textEvent
, status
);
352 nsCompositionEvent
compEvent(true, NS_COMPOSITION_END
, this);
353 InitEvent(compEvent
, nullptr);
354 compEvent
.seqno
= mIMELastReceivedSeqno
;
355 DispatchEvent(&compEvent
, status
);
360 PuppetWidget::ResetInputState()
362 return IMEEndComposition(false);
366 PuppetWidget::CancelComposition()
368 return IMEEndComposition(true);
372 PuppetWidget::SetInputContext(const InputContext
& aContext
,
373 const InputContextAction
& aAction
)
378 mTabChild
->SendSetInputContext(
379 static_cast<int32_t>(aContext
.mIMEState
.mEnabled
),
380 static_cast<int32_t>(aContext
.mIMEState
.mOpen
),
381 aContext
.mHTMLInputType
,
382 aContext
.mHTMLInputInputmode
,
383 aContext
.mActionHint
,
384 static_cast<int32_t>(aAction
.mCause
),
385 static_cast<int32_t>(aAction
.mFocusChange
));
388 NS_IMETHODIMP_(InputContext
)
389 PuppetWidget::GetInputContext()
391 InputContext context
;
393 int32_t enabled
, open
;
394 mTabChild
->SendGetInputContext(&enabled
, &open
);
395 context
.mIMEState
.mEnabled
= static_cast<IMEState::Enabled
>(enabled
);
396 context
.mIMEState
.mOpen
= static_cast<IMEState::Open
>(open
);
402 PuppetWidget::OnIMEFocusChange(bool aFocus
)
405 return NS_ERROR_FAILURE
;
408 nsEventStatus status
;
409 nsQueryContentEvent
queryEvent(true, NS_QUERY_TEXT_CONTENT
, this);
410 InitEvent(queryEvent
, nullptr);
411 // Query entire content
412 queryEvent
.InitForQueryTextContent(0, UINT32_MAX
);
413 DispatchEvent(&queryEvent
, status
);
415 if (queryEvent
.mSucceeded
) {
416 mTabChild
->SendNotifyIMETextHint(queryEvent
.mReply
.mString
);
419 // ResetInputState might not have been called yet
423 uint32_t chromeSeqno
;
424 mIMEPreference
.mWantUpdates
= false;
425 mIMEPreference
.mWantHints
= false;
426 if (!mTabChild
->SendNotifyIMEFocus(aFocus
, &mIMEPreference
, &chromeSeqno
))
427 return NS_ERROR_FAILURE
;
430 if (!mIMEPreference
.mWantUpdates
&& !mIMEPreference
.mWantHints
)
431 // call OnIMEFocusChange on blur but no other updates
432 return NS_SUCCESS_IME_NO_UPDATES
;
433 OnIMESelectionChange(); // Update selection
435 mIMELastBlurSeqno
= chromeSeqno
;
441 PuppetWidget::OnIMETextChange(uint32_t aStart
, uint32_t aEnd
, uint32_t aNewEnd
)
444 return NS_ERROR_FAILURE
;
446 if (mIMEPreference
.mWantHints
) {
447 nsEventStatus status
;
448 nsQueryContentEvent
queryEvent(true, NS_QUERY_TEXT_CONTENT
, this);
449 InitEvent(queryEvent
, nullptr);
450 queryEvent
.InitForQueryTextContent(0, UINT32_MAX
);
451 DispatchEvent(&queryEvent
, status
);
453 if (queryEvent
.mSucceeded
) {
454 mTabChild
->SendNotifyIMETextHint(queryEvent
.mReply
.mString
);
457 if (mIMEPreference
.mWantUpdates
) {
458 mTabChild
->SendNotifyIMETextChange(aStart
, aEnd
, aNewEnd
);
464 PuppetWidget::OnIMESelectionChange(void)
467 return NS_ERROR_FAILURE
;
469 if (mIMEPreference
.mWantUpdates
) {
470 nsEventStatus status
;
471 nsQueryContentEvent
queryEvent(true, NS_QUERY_SELECTED_TEXT
, this);
472 InitEvent(queryEvent
, nullptr);
473 DispatchEvent(&queryEvent
, status
);
475 if (queryEvent
.mSucceeded
) {
476 mTabChild
->SendNotifyIMESelection(mIMELastReceivedSeqno
,
477 queryEvent
.GetSelectionStart(),
478 queryEvent
.GetSelectionEnd());
485 PuppetWidget::SetCursor(nsCursor aCursor
)
487 if (mCursor
== aCursor
) {
492 !mTabChild
->SendSetCursor(aCursor
)) {
493 return NS_ERROR_FAILURE
;
502 PuppetWidget::Paint()
504 NS_ABORT_IF_FALSE(!mDirtyRegion
.IsEmpty(), "paint event logic messed up");
506 if (!mAttachedWidgetListener
)
509 nsIntRegion region
= mDirtyRegion
;
511 // reset repaint tracking
512 mDirtyRegion
.SetEmpty();
517 debug_DumpPaintEvent(stderr
, this, region
,
518 nsAutoCString("PuppetWidget"), 0);
521 if (mozilla::layers::LAYERS_D3D10
== mLayerManager
->GetBackendType()) {
522 mAttachedWidgetListener
->PaintWindow(this, region
, false, true);
524 nsRefPtr
<gfxContext
> ctx
= new gfxContext(mSurface
);
525 ctx
->Rectangle(gfxRect(0,0,0,0));
527 AutoLayerManagerSetup
setupLayerManager(this, ctx
,
529 mAttachedWidgetListener
->PaintWindow(this, region
, false, true);
530 mTabChild
->NotifyPainted();
534 if (mAttachedWidgetListener
) {
535 mAttachedWidgetListener
->DidPaintWindow();
542 PuppetWidget::SetChild(PuppetWidget
* aChild
)
544 NS_ABORT_IF_FALSE(this != aChild
, "can't parent a widget to itself");
545 NS_ABORT_IF_FALSE(!aChild
->mChild
,
546 "fake widget 'hierarchy' only expected to have one level");
552 PuppetWidget::PaintTask::Run()
561 PuppetWidget::NeedsPaint()
567 PuppetWidget::GetDPI()
570 NS_ABORT_IF_FALSE(mTabChild
, "Need TabChild to get the DPI from!");
571 mTabChild
->GetDPI(&mDPI
);
578 PuppetWidget::GetNativeData(uint32_t aDataType
)
581 case NS_NATIVE_SHAREABLE_WINDOW
: {
582 NS_ABORT_IF_FALSE(mTabChild
, "Need TabChild to get the nativeWindow from!");
583 mozilla::WindowsHandle nativeData
= 0;
584 mTabChild
->SendGetWidgetNativeData(&nativeData
);
585 return (void*)nativeData
;
587 case NS_NATIVE_WINDOW
:
588 case NS_NATIVE_DISPLAY
:
589 case NS_NATIVE_PLUGIN_PORT
:
590 case NS_NATIVE_GRAPHIC
:
591 case NS_NATIVE_SHELLWIDGET
:
592 case NS_NATIVE_WIDGET
:
593 NS_WARNING("nsWindow::GetNativeData not implemented for this type");
596 NS_WARNING("nsWindow::GetNativeData called with bad value");
602 PuppetScreen::PuppetScreen(void *nativeScreen
)
606 PuppetScreen::~PuppetScreen()
610 static ScreenConfiguration
613 ScreenConfiguration config
;
614 hal::GetCurrentScreenConfiguration(&config
);
619 PuppetScreen::GetRect(int32_t *outLeft
, int32_t *outTop
,
620 int32_t *outWidth
, int32_t *outHeight
)
622 nsIntRect r
= ScreenConfig().rect();
626 *outHeight
= r
.height
;
631 PuppetScreen::GetAvailRect(int32_t *outLeft
, int32_t *outTop
,
632 int32_t *outWidth
, int32_t *outHeight
)
634 return GetRect(outLeft
, outTop
, outWidth
, outHeight
);
639 PuppetScreen::GetPixelDepth(int32_t *aPixelDepth
)
641 *aPixelDepth
= ScreenConfig().pixelDepth();
646 PuppetScreen::GetColorDepth(int32_t *aColorDepth
)
648 *aColorDepth
= ScreenConfig().colorDepth();
653 PuppetScreen::GetRotation(uint32_t* aRotation
)
655 NS_WARNING("Attempt to get screen rotation through nsIScreen::GetRotation(). Nothing should know or care this in sandboxed contexts. If you want *orientation*, use hal.");
656 return NS_ERROR_NOT_AVAILABLE
;
660 PuppetScreen::SetRotation(uint32_t aRotation
)
662 NS_WARNING("Attempt to set screen rotation through nsIScreen::GetRotation(). Nothing should know or care this in sandboxed contexts. If you want *orientation*, use hal.");
663 return NS_ERROR_NOT_AVAILABLE
;
666 NS_IMPL_ISUPPORTS1(PuppetScreenManager
, nsIScreenManager
)
668 PuppetScreenManager::PuppetScreenManager()
670 mOneScreen
= new PuppetScreen(nullptr);
673 PuppetScreenManager::~PuppetScreenManager()
678 PuppetScreenManager::GetPrimaryScreen(nsIScreen
** outScreen
)
680 NS_IF_ADDREF(*outScreen
= mOneScreen
.get());
685 PuppetScreenManager::ScreenForRect(int32_t inLeft
,
689 nsIScreen
** outScreen
)
691 return GetPrimaryScreen(outScreen
);
695 PuppetScreenManager::ScreenForNativeWidget(void* aWidget
,
696 nsIScreen
** outScreen
)
698 return GetPrimaryScreen(outScreen
);
702 PuppetScreenManager::GetNumberOfScreens(uint32_t* aNumberOfScreens
)
704 *aNumberOfScreens
= 1;
708 } // namespace widget
709 } // namespace mozilla