michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=8 et : michael@0: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "base/basictypes.h" michael@0: michael@0: #include "ClientLayerManager.h" michael@0: #include "gfxPlatform.h" michael@0: #if defined(MOZ_ENABLE_D3D10_LAYER) michael@0: # include "LayerManagerD3D10.h" michael@0: #endif michael@0: #include "mozilla/dom/TabChild.h" michael@0: #include "mozilla/Hal.h" michael@0: #include "mozilla/IMEStateManager.h" michael@0: #include "mozilla/layers/CompositorChild.h" michael@0: #include "mozilla/layers/PLayerTransactionChild.h" michael@0: #include "mozilla/TextComposition.h" michael@0: #include "mozilla/TextEvents.h" michael@0: #include "PuppetWidget.h" michael@0: #include "nsIWidgetListener.h" michael@0: michael@0: using namespace mozilla::dom; michael@0: using namespace mozilla::hal; michael@0: using namespace mozilla::gfx; michael@0: using namespace mozilla::layers; michael@0: using namespace mozilla::widget; michael@0: michael@0: static void michael@0: InvalidateRegion(nsIWidget* aWidget, const nsIntRegion& aRegion) michael@0: { michael@0: nsIntRegionRectIterator it(aRegion); michael@0: while(const nsIntRect* r = it.Next()) { michael@0: aWidget->Invalidate(*r); michael@0: } michael@0: } michael@0: michael@0: /*static*/ already_AddRefed michael@0: nsIWidget::CreatePuppetWidget(TabChild* aTabChild) michael@0: { michael@0: NS_ABORT_IF_FALSE(!aTabChild || nsIWidget::UsePuppetWidgets(), michael@0: "PuppetWidgets not allowed in this configuration"); michael@0: michael@0: nsCOMPtr widget = new PuppetWidget(aTabChild); michael@0: return widget.forget(); michael@0: } michael@0: michael@0: namespace mozilla { michael@0: namespace widget { michael@0: michael@0: static bool michael@0: IsPopup(const nsWidgetInitData* aInitData) michael@0: { michael@0: return aInitData && aInitData->mWindowType == eWindowType_popup; michael@0: } michael@0: michael@0: static bool michael@0: MightNeedIMEFocus(const nsWidgetInitData* aInitData) michael@0: { michael@0: // In the puppet-widget world, popup widgets are just dummies and michael@0: // shouldn't try to mess with IME state. michael@0: #ifdef MOZ_CROSS_PROCESS_IME michael@0: return !IsPopup(aInitData); michael@0: #else michael@0: return false; michael@0: #endif michael@0: } michael@0: michael@0: michael@0: // Arbitrary, fungible. michael@0: const size_t PuppetWidget::kMaxDimension = 4000; michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(PuppetWidget, nsBaseWidget, michael@0: nsISupportsWeakReference) michael@0: michael@0: PuppetWidget::PuppetWidget(TabChild* aTabChild) michael@0: : mTabChild(aTabChild) michael@0: , mDPI(-1) michael@0: , mDefaultScale(-1) michael@0: , mNativeKeyCommandsValid(false) michael@0: { michael@0: MOZ_COUNT_CTOR(PuppetWidget); michael@0: michael@0: mSingleLineCommands.SetCapacity(4); michael@0: mMultiLineCommands.SetCapacity(4); michael@0: mRichTextCommands.SetCapacity(4); michael@0: } michael@0: michael@0: PuppetWidget::~PuppetWidget() michael@0: { michael@0: MOZ_COUNT_DTOR(PuppetWidget); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetWidget::Create(nsIWidget *aParent, michael@0: nsNativeWidget aNativeParent, michael@0: const nsIntRect &aRect, michael@0: nsDeviceContext *aContext, michael@0: nsWidgetInitData *aInitData) michael@0: { michael@0: NS_ABORT_IF_FALSE(!aNativeParent, "got a non-Puppet native parent"); michael@0: michael@0: BaseCreate(nullptr, aRect, aContext, aInitData); michael@0: michael@0: mBounds = aRect; michael@0: mEnabled = true; michael@0: mVisible = true; michael@0: michael@0: mSurface = gfxPlatform::GetPlatform() michael@0: ->CreateOffscreenSurface(IntSize(1, 1), michael@0: gfxASurface::ContentFromFormat(gfxImageFormat::ARGB32)); michael@0: michael@0: mIMEComposing = false; michael@0: mNeedIMEStateInit = MightNeedIMEFocus(aInitData); michael@0: michael@0: PuppetWidget* parent = static_cast(aParent); michael@0: if (parent) { michael@0: parent->SetChild(this); michael@0: mLayerManager = parent->GetLayerManager(); michael@0: } michael@0: else { michael@0: Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: PuppetWidget::InitIMEState() michael@0: { michael@0: MOZ_ASSERT(mTabChild); michael@0: if (mNeedIMEStateInit) { michael@0: uint32_t chromeSeqno; michael@0: mTabChild->SendNotifyIMEFocus(false, &mIMEPreferenceOfParent, &chromeSeqno); michael@0: mIMELastBlurSeqno = mIMELastReceivedSeqno = chromeSeqno; michael@0: mNeedIMEStateInit = false; michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: PuppetWidget::CreateChild(const nsIntRect &aRect, michael@0: nsDeviceContext *aContext, michael@0: nsWidgetInitData *aInitData, michael@0: bool aForceUseIWidgetParent) michael@0: { michael@0: bool isPopup = IsPopup(aInitData); michael@0: nsCOMPtr widget = nsIWidget::CreatePuppetWidget(mTabChild); michael@0: return ((widget && michael@0: NS_SUCCEEDED(widget->Create(isPopup ? nullptr: this, nullptr, aRect, michael@0: aContext, aInitData))) ? michael@0: widget.forget() : nullptr); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetWidget::Destroy() michael@0: { michael@0: Base::OnDestroy(); michael@0: Base::Destroy(); michael@0: mPaintTask.Revoke(); michael@0: mChild = nullptr; michael@0: if (mLayerManager) { michael@0: mLayerManager->Destroy(); michael@0: } michael@0: mLayerManager = nullptr; michael@0: mTabChild = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetWidget::Show(bool aState) michael@0: { michael@0: NS_ASSERTION(mEnabled, michael@0: "does it make sense to Show()/Hide() a disabled widget?"); michael@0: michael@0: bool wasVisible = mVisible; michael@0: mVisible = aState; michael@0: michael@0: if (mChild) { michael@0: mChild->mVisible = aState; michael@0: } michael@0: michael@0: if (!mVisible && mLayerManager) { michael@0: mLayerManager->ClearCachedResources(); michael@0: } michael@0: michael@0: if (!wasVisible && mVisible) { michael@0: Resize(mBounds.width, mBounds.height, false); michael@0: Invalidate(mBounds); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetWidget::Resize(double aWidth, michael@0: double aHeight, michael@0: bool aRepaint) michael@0: { michael@0: nsIntRect oldBounds = mBounds; michael@0: mBounds.SizeTo(nsIntSize(NSToIntRound(aWidth), NSToIntRound(aHeight))); michael@0: michael@0: if (mChild) { michael@0: return mChild->Resize(aWidth, aHeight, aRepaint); michael@0: } michael@0: michael@0: // XXX: roc says that |aRepaint| dictates whether or not to michael@0: // invalidate the expanded area michael@0: if (oldBounds.Size() < mBounds.Size() && aRepaint) { michael@0: nsIntRegion dirty(mBounds); michael@0: dirty.Sub(dirty, oldBounds); michael@0: InvalidateRegion(this, dirty); michael@0: } michael@0: michael@0: if (!oldBounds.IsEqualEdges(mBounds) && mAttachedWidgetListener) { michael@0: mAttachedWidgetListener->WindowResized(this, mBounds.width, mBounds.height); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetWidget::SetFocus(bool aRaise) michael@0: { michael@0: // XXX/cjones: someone who knows about event handling needs to michael@0: // decide how this should work. michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetWidget::Invalidate(const nsIntRect& aRect) michael@0: { michael@0: #ifdef DEBUG michael@0: debug_DumpInvalidate(stderr, this, &aRect, michael@0: nsAutoCString("PuppetWidget"), 0); michael@0: #endif michael@0: michael@0: if (mChild) { michael@0: return mChild->Invalidate(aRect); michael@0: } michael@0: michael@0: mDirtyRegion.Or(mDirtyRegion, aRect); michael@0: michael@0: if (!mDirtyRegion.IsEmpty() && !mPaintTask.IsPending()) { michael@0: mPaintTask = new PaintTask(this); michael@0: return NS_DispatchToCurrentThread(mPaintTask.get()); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: PuppetWidget::InitEvent(WidgetGUIEvent& event, nsIntPoint* aPoint) michael@0: { michael@0: if (nullptr == aPoint) { michael@0: event.refPoint.x = 0; michael@0: event.refPoint.y = 0; michael@0: } michael@0: else { michael@0: // use the point override if provided michael@0: event.refPoint.x = aPoint->x; michael@0: event.refPoint.y = aPoint->y; michael@0: } michael@0: event.time = PR_Now() / 1000; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus) michael@0: { michael@0: #ifdef DEBUG michael@0: debug_DumpEvent(stdout, event->widget, event, michael@0: nsAutoCString("PuppetWidget"), 0); michael@0: #endif michael@0: michael@0: NS_ABORT_IF_FALSE(!mChild || mChild->mWindowType == eWindowType_popup, michael@0: "Unexpected event dispatch!"); michael@0: michael@0: AutoCacheNativeKeyCommands autoCache(this); michael@0: if (event->mFlags.mIsSynthesizedForTests && !mNativeKeyCommandsValid) { michael@0: WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent(); michael@0: if (keyEvent) { michael@0: mTabChild->RequestNativeKeyBindings(&autoCache, keyEvent); michael@0: } michael@0: } michael@0: michael@0: aStatus = nsEventStatus_eIgnore; michael@0: michael@0: if (event->message == NS_COMPOSITION_START) { michael@0: mIMEComposing = true; michael@0: } michael@0: uint32_t seqno = kLatestSeqno; michael@0: switch (event->eventStructType) { michael@0: case NS_COMPOSITION_EVENT: michael@0: seqno = event->AsCompositionEvent()->mSeqno; michael@0: break; michael@0: case NS_TEXT_EVENT: michael@0: seqno = event->AsTextEvent()->mSeqno; michael@0: break; michael@0: case NS_SELECTION_EVENT: michael@0: seqno = event->AsSelectionEvent()->mSeqno; michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: if (seqno != kLatestSeqno) { michael@0: mIMELastReceivedSeqno = seqno; michael@0: if (mIMELastReceivedSeqno < mIMELastBlurSeqno) { michael@0: return NS_OK; michael@0: } michael@0: } michael@0: michael@0: if (mAttachedWidgetListener) { michael@0: aStatus = mAttachedWidgetListener->HandleEvent(event, mUseAttachedEvents); michael@0: } michael@0: michael@0: if (event->message == NS_COMPOSITION_END) { michael@0: mIMEComposing = false; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP_(bool) michael@0: PuppetWidget::ExecuteNativeKeyBinding(NativeKeyBindingsType aType, michael@0: const mozilla::WidgetKeyboardEvent& aEvent, michael@0: DoCommandCallback aCallback, michael@0: void* aCallbackData) michael@0: { michael@0: // B2G doesn't have native key bindings. michael@0: #ifdef MOZ_B2G michael@0: return false; michael@0: #else // #ifdef MOZ_B2G michael@0: MOZ_ASSERT(mNativeKeyCommandsValid); michael@0: michael@0: nsTArray& commands = mSingleLineCommands; michael@0: switch (aType) { michael@0: case nsIWidget::NativeKeyBindingsForSingleLineEditor: michael@0: commands = mSingleLineCommands; michael@0: break; michael@0: case nsIWidget::NativeKeyBindingsForMultiLineEditor: michael@0: commands = mMultiLineCommands; michael@0: break; michael@0: case nsIWidget::NativeKeyBindingsForRichTextEditor: michael@0: commands = mRichTextCommands; michael@0: break; michael@0: } michael@0: michael@0: if (commands.IsEmpty()) { michael@0: return false; michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < commands.Length(); i++) { michael@0: aCallback(static_cast(commands[i]), aCallbackData); michael@0: } michael@0: return true; michael@0: #endif michael@0: } michael@0: michael@0: LayerManager* michael@0: PuppetWidget::GetLayerManager(PLayerTransactionChild* aShadowManager, michael@0: LayersBackend aBackendHint, michael@0: LayerManagerPersistence aPersistence, michael@0: bool* aAllowRetaining) michael@0: { michael@0: if (!mLayerManager) { michael@0: // The backend hint is a temporary placeholder until Azure, when michael@0: // all content-process layer managers will be BasicLayerManagers. michael@0: #if defined(MOZ_ENABLE_D3D10_LAYER) michael@0: if (mozilla::layers::LayersBackend::LAYERS_D3D10 == aBackendHint) { michael@0: nsRefPtr m = new LayerManagerD3D10(this); michael@0: m->AsShadowForwarder()->SetShadowManager(aShadowManager); michael@0: if (m->Initialize()) { michael@0: mLayerManager = m; michael@0: } michael@0: } michael@0: #endif michael@0: if (!mLayerManager) { michael@0: mLayerManager = new ClientLayerManager(this); michael@0: } michael@0: } michael@0: ShadowLayerForwarder* lf = mLayerManager->AsShadowForwarder(); michael@0: if (!lf->HasShadowManager() && aShadowManager) { michael@0: lf->SetShadowManager(aShadowManager); michael@0: } michael@0: if (aAllowRetaining) { michael@0: *aAllowRetaining = true; michael@0: } michael@0: return mLayerManager; michael@0: } michael@0: michael@0: gfxASurface* michael@0: PuppetWidget::GetThebesSurface() michael@0: { michael@0: return mSurface; michael@0: } michael@0: michael@0: nsresult michael@0: PuppetWidget::IMEEndComposition(bool aCancel) michael@0: { michael@0: #ifndef MOZ_CROSS_PROCESS_IME michael@0: return NS_OK; michael@0: #endif michael@0: michael@0: nsEventStatus status; michael@0: WidgetTextEvent textEvent(true, NS_TEXT_TEXT, this); michael@0: InitEvent(textEvent, nullptr); michael@0: textEvent.mSeqno = mIMELastReceivedSeqno; michael@0: // SendEndIMEComposition is always called since ResetInputState michael@0: // should always be called even if we aren't composing something. michael@0: if (!mTabChild || michael@0: !mTabChild->SendEndIMEComposition(aCancel, &textEvent.theText)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (!mIMEComposing) michael@0: return NS_OK; michael@0: michael@0: DispatchEvent(&textEvent, status); michael@0: michael@0: WidgetCompositionEvent compEvent(true, NS_COMPOSITION_END, this); michael@0: InitEvent(compEvent, nullptr); michael@0: compEvent.mSeqno = mIMELastReceivedSeqno; michael@0: DispatchEvent(&compEvent, status); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetWidget::NotifyIME(const IMENotification& aIMENotification) michael@0: { michael@0: switch (aIMENotification.mMessage) { michael@0: case NOTIFY_IME_OF_CURSOR_POS_CHANGED: michael@0: case REQUEST_TO_COMMIT_COMPOSITION: michael@0: return IMEEndComposition(false); michael@0: case REQUEST_TO_CANCEL_COMPOSITION: michael@0: return IMEEndComposition(true); michael@0: case NOTIFY_IME_OF_FOCUS: michael@0: return NotifyIMEOfFocusChange(true); michael@0: case NOTIFY_IME_OF_BLUR: michael@0: return NotifyIMEOfFocusChange(false); michael@0: case NOTIFY_IME_OF_SELECTION_CHANGE: michael@0: return NotifyIMEOfSelectionChange(aIMENotification); michael@0: case NOTIFY_IME_OF_TEXT_CHANGE: michael@0: return NotifyIMEOfTextChange(aIMENotification); michael@0: case NOTIFY_IME_OF_COMPOSITION_UPDATE: michael@0: return NotifyIMEOfUpdateComposition(); michael@0: default: michael@0: return NS_ERROR_NOT_IMPLEMENTED; michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP_(void) michael@0: PuppetWidget::SetInputContext(const InputContext& aContext, michael@0: const InputContextAction& aAction) michael@0: { michael@0: #ifndef MOZ_CROSS_PROCESS_IME michael@0: return; michael@0: #endif michael@0: michael@0: if (!mTabChild) { michael@0: return; michael@0: } michael@0: mTabChild->SendSetInputContext( michael@0: static_cast(aContext.mIMEState.mEnabled), michael@0: static_cast(aContext.mIMEState.mOpen), michael@0: aContext.mHTMLInputType, michael@0: aContext.mHTMLInputInputmode, michael@0: aContext.mActionHint, michael@0: static_cast(aAction.mCause), michael@0: static_cast(aAction.mFocusChange)); michael@0: } michael@0: michael@0: NS_IMETHODIMP_(InputContext) michael@0: PuppetWidget::GetInputContext() michael@0: { michael@0: #ifndef MOZ_CROSS_PROCESS_IME michael@0: return InputContext(); michael@0: #endif michael@0: michael@0: InputContext context; michael@0: if (mTabChild) { michael@0: int32_t enabled, open; michael@0: intptr_t nativeIMEContext; michael@0: mTabChild->SendGetInputContext(&enabled, &open, &nativeIMEContext); michael@0: context.mIMEState.mEnabled = static_cast(enabled); michael@0: context.mIMEState.mOpen = static_cast(open); michael@0: context.mNativeIMEContext = reinterpret_cast(nativeIMEContext); michael@0: } michael@0: return context; michael@0: } michael@0: michael@0: nsresult michael@0: PuppetWidget::NotifyIMEOfFocusChange(bool aFocus) michael@0: { michael@0: #ifndef MOZ_CROSS_PROCESS_IME michael@0: return NS_OK; michael@0: #endif michael@0: michael@0: if (!mTabChild) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: if (aFocus) { michael@0: nsEventStatus status; michael@0: WidgetQueryContentEvent queryEvent(true, NS_QUERY_TEXT_CONTENT, this); michael@0: InitEvent(queryEvent, nullptr); michael@0: // Query entire content michael@0: queryEvent.InitForQueryTextContent(0, UINT32_MAX); michael@0: DispatchEvent(&queryEvent, status); michael@0: michael@0: if (queryEvent.mSucceeded) { michael@0: mTabChild->SendNotifyIMETextHint(queryEvent.mReply.mString); michael@0: } michael@0: } else { michael@0: // Might not have been committed composition yet michael@0: IMEEndComposition(false); michael@0: } michael@0: michael@0: uint32_t chromeSeqno; michael@0: mIMEPreferenceOfParent = nsIMEUpdatePreference(); michael@0: if (!mTabChild->SendNotifyIMEFocus(aFocus, &mIMEPreferenceOfParent, michael@0: &chromeSeqno)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: if (aFocus) { michael@0: IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE); michael@0: notification.mSelectionChangeData.mCausedByComposition = false; michael@0: NotifyIMEOfSelectionChange(notification); // Update selection michael@0: } else { michael@0: mIMELastBlurSeqno = chromeSeqno; michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: PuppetWidget::NotifyIMEOfUpdateComposition() michael@0: { michael@0: #ifndef MOZ_CROSS_PROCESS_IME michael@0: return NS_OK; michael@0: #endif michael@0: michael@0: NS_ENSURE_TRUE(mTabChild, NS_ERROR_FAILURE); michael@0: michael@0: nsRefPtr textComposition = michael@0: IMEStateManager::GetTextCompositionFor(this); michael@0: NS_ENSURE_TRUE(textComposition, NS_ERROR_FAILURE); michael@0: michael@0: nsEventStatus status; michael@0: uint32_t offset = textComposition->OffsetOfTargetClause(); michael@0: WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, this); michael@0: InitEvent(textRect, nullptr); michael@0: textRect.InitForQueryTextRect(offset, 1); michael@0: DispatchEvent(&textRect, status); michael@0: NS_ENSURE_TRUE(textRect.mSucceeded, NS_ERROR_FAILURE); michael@0: michael@0: WidgetQueryContentEvent caretRect(true, NS_QUERY_CARET_RECT, this); michael@0: InitEvent(caretRect, nullptr); michael@0: caretRect.InitForQueryCaretRect(offset); michael@0: DispatchEvent(&caretRect, status); michael@0: NS_ENSURE_TRUE(caretRect.mSucceeded, NS_ERROR_FAILURE); michael@0: michael@0: mTabChild->SendNotifyIMESelectedCompositionRect(offset, michael@0: textRect.mReply.mRect, michael@0: caretRect.mReply.mRect); michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsIMEUpdatePreference michael@0: PuppetWidget::GetIMEUpdatePreference() michael@0: { michael@0: #ifdef MOZ_CROSS_PROCESS_IME michael@0: // e10s requires IME information cache into TabParent michael@0: return nsIMEUpdatePreference(mIMEPreferenceOfParent.mWantUpdates | michael@0: nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE | michael@0: nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE); michael@0: #else michael@0: // B2G doesn't handle IME as widget-level. michael@0: return nsIMEUpdatePreference(); michael@0: #endif michael@0: } michael@0: michael@0: nsresult michael@0: PuppetWidget::NotifyIMEOfTextChange(const IMENotification& aIMENotification) michael@0: { michael@0: MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE, michael@0: "Passed wrong notification"); michael@0: michael@0: #ifndef MOZ_CROSS_PROCESS_IME michael@0: return NS_OK; michael@0: #endif michael@0: michael@0: if (!mTabChild) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsEventStatus status; michael@0: WidgetQueryContentEvent queryEvent(true, NS_QUERY_TEXT_CONTENT, this); michael@0: InitEvent(queryEvent, nullptr); michael@0: queryEvent.InitForQueryTextContent(0, UINT32_MAX); michael@0: DispatchEvent(&queryEvent, status); michael@0: michael@0: if (queryEvent.mSucceeded) { michael@0: mTabChild->SendNotifyIMETextHint(queryEvent.mReply.mString); michael@0: } michael@0: michael@0: // TabParent doesn't this this to cache. we don't send the notification michael@0: // if parent process doesn't request NOTIFY_TEXT_CHANGE. michael@0: if (mIMEPreferenceOfParent.WantTextChange() && michael@0: (mIMEPreferenceOfParent.WantChangesCausedByComposition() || michael@0: !aIMENotification.mTextChangeData.mCausedByComposition)) { michael@0: mTabChild->SendNotifyIMETextChange( michael@0: aIMENotification.mTextChangeData.mStartOffset, michael@0: aIMENotification.mTextChangeData.mOldEndOffset, michael@0: aIMENotification.mTextChangeData.mNewEndOffset, michael@0: aIMENotification.mTextChangeData.mCausedByComposition); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: PuppetWidget::NotifyIMEOfSelectionChange( michael@0: const IMENotification& aIMENotification) michael@0: { michael@0: MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE, michael@0: "Passed wrong notification"); michael@0: michael@0: #ifndef MOZ_CROSS_PROCESS_IME michael@0: return NS_OK; michael@0: #endif michael@0: michael@0: if (!mTabChild) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsEventStatus status; michael@0: WidgetQueryContentEvent queryEvent(true, NS_QUERY_SELECTED_TEXT, this); michael@0: InitEvent(queryEvent, nullptr); michael@0: DispatchEvent(&queryEvent, status); michael@0: michael@0: if (queryEvent.mSucceeded) { michael@0: mTabChild->SendNotifyIMESelection( michael@0: mIMELastReceivedSeqno, michael@0: queryEvent.GetSelectionStart(), michael@0: queryEvent.GetSelectionEnd(), michael@0: aIMENotification.mSelectionChangeData.mCausedByComposition); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetWidget::SetCursor(nsCursor aCursor) michael@0: { michael@0: if (mCursor == aCursor) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (mTabChild && !mTabChild->SendSetCursor(aCursor)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: mCursor = aCursor; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsresult michael@0: PuppetWidget::Paint() michael@0: { michael@0: NS_ABORT_IF_FALSE(!mDirtyRegion.IsEmpty(), "paint event logic messed up"); michael@0: michael@0: if (!mAttachedWidgetListener) michael@0: return NS_OK; michael@0: michael@0: nsIntRegion region = mDirtyRegion; michael@0: michael@0: // reset repaint tracking michael@0: mDirtyRegion.SetEmpty(); michael@0: mPaintTask.Revoke(); michael@0: michael@0: mAttachedWidgetListener->WillPaintWindow(this); michael@0: michael@0: if (mAttachedWidgetListener) { michael@0: #ifdef DEBUG michael@0: debug_DumpPaintEvent(stderr, this, region, michael@0: nsAutoCString("PuppetWidget"), 0); michael@0: #endif michael@0: michael@0: if (mozilla::layers::LayersBackend::LAYERS_D3D10 == mLayerManager->GetBackendType()) { michael@0: mAttachedWidgetListener->PaintWindow(this, region); michael@0: } else if (mozilla::layers::LayersBackend::LAYERS_CLIENT == mLayerManager->GetBackendType()) { michael@0: // Do nothing, the compositor will handle drawing michael@0: if (mTabChild) { michael@0: mTabChild->NotifyPainted(); michael@0: } michael@0: } else { michael@0: nsRefPtr ctx = new gfxContext(mSurface); michael@0: ctx->Rectangle(gfxRect(0,0,0,0)); michael@0: ctx->Clip(); michael@0: AutoLayerManagerSetup setupLayerManager(this, ctx, michael@0: BufferMode::BUFFER_NONE); michael@0: mAttachedWidgetListener->PaintWindow(this, region); michael@0: if (mTabChild) { michael@0: mTabChild->NotifyPainted(); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (mAttachedWidgetListener) { michael@0: mAttachedWidgetListener->DidPaintWindow(); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: void michael@0: PuppetWidget::SetChild(PuppetWidget* aChild) michael@0: { michael@0: NS_ABORT_IF_FALSE(this != aChild, "can't parent a widget to itself"); michael@0: NS_ABORT_IF_FALSE(!aChild->mChild, michael@0: "fake widget 'hierarchy' only expected to have one level"); michael@0: michael@0: mChild = aChild; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetWidget::PaintTask::Run() michael@0: { michael@0: if (mWidget) { michael@0: mWidget->Paint(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: PuppetWidget::NeedsPaint() michael@0: { michael@0: return mVisible; michael@0: } michael@0: michael@0: float michael@0: PuppetWidget::GetDPI() michael@0: { michael@0: if (mDPI < 0) { michael@0: if (mTabChild) { michael@0: mTabChild->GetDPI(&mDPI); michael@0: } else { michael@0: mDPI = 96.0; michael@0: } michael@0: } michael@0: michael@0: return mDPI; michael@0: } michael@0: michael@0: double michael@0: PuppetWidget::GetDefaultScaleInternal() michael@0: { michael@0: if (mDefaultScale < 0) { michael@0: if (mTabChild) { michael@0: mTabChild->GetDefaultScale(&mDefaultScale); michael@0: } else { michael@0: mDefaultScale = 1; michael@0: } michael@0: } michael@0: michael@0: return mDefaultScale; michael@0: } michael@0: michael@0: void* michael@0: PuppetWidget::GetNativeData(uint32_t aDataType) michael@0: { michael@0: switch (aDataType) { michael@0: case NS_NATIVE_SHAREABLE_WINDOW: { michael@0: NS_ABORT_IF_FALSE(mTabChild, "Need TabChild to get the nativeWindow from!"); michael@0: mozilla::WindowsHandle nativeData = 0; michael@0: if (mTabChild) { michael@0: mTabChild->SendGetWidgetNativeData(&nativeData); michael@0: } michael@0: return (void*)nativeData; michael@0: } michael@0: case NS_NATIVE_WINDOW: michael@0: case NS_NATIVE_DISPLAY: michael@0: case NS_NATIVE_PLUGIN_PORT: michael@0: case NS_NATIVE_GRAPHIC: michael@0: case NS_NATIVE_SHELLWIDGET: michael@0: case NS_NATIVE_WIDGET: michael@0: NS_WARNING("nsWindow::GetNativeData not implemented for this type"); michael@0: break; michael@0: default: michael@0: NS_WARNING("nsWindow::GetNativeData called with bad value"); michael@0: break; michael@0: } michael@0: return nullptr; michael@0: } michael@0: michael@0: PuppetScreen::PuppetScreen(void *nativeScreen) michael@0: { michael@0: } michael@0: michael@0: PuppetScreen::~PuppetScreen() michael@0: { michael@0: } michael@0: michael@0: static ScreenConfiguration michael@0: ScreenConfig() michael@0: { michael@0: ScreenConfiguration config; michael@0: hal::GetCurrentScreenConfiguration(&config); michael@0: return config; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreen::GetRect(int32_t *outLeft, int32_t *outTop, michael@0: int32_t *outWidth, int32_t *outHeight) michael@0: { michael@0: nsIntRect r = ScreenConfig().rect(); michael@0: *outLeft = r.x; michael@0: *outTop = r.y; michael@0: *outWidth = r.width; michael@0: *outHeight = r.height; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreen::GetAvailRect(int32_t *outLeft, int32_t *outTop, michael@0: int32_t *outWidth, int32_t *outHeight) michael@0: { michael@0: return GetRect(outLeft, outTop, outWidth, outHeight); michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreen::GetPixelDepth(int32_t *aPixelDepth) michael@0: { michael@0: *aPixelDepth = ScreenConfig().pixelDepth(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreen::GetColorDepth(int32_t *aColorDepth) michael@0: { michael@0: *aColorDepth = ScreenConfig().colorDepth(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreen::GetRotation(uint32_t* aRotation) michael@0: { michael@0: 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."); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreen::SetRotation(uint32_t aRotation) michael@0: { michael@0: 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."); michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(PuppetScreenManager, nsIScreenManager) michael@0: michael@0: PuppetScreenManager::PuppetScreenManager() michael@0: { michael@0: mOneScreen = new PuppetScreen(nullptr); michael@0: } michael@0: michael@0: PuppetScreenManager::~PuppetScreenManager() michael@0: { michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreenManager::GetPrimaryScreen(nsIScreen** outScreen) michael@0: { michael@0: NS_IF_ADDREF(*outScreen = mOneScreen.get()); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreenManager::ScreenForRect(int32_t inLeft, michael@0: int32_t inTop, michael@0: int32_t inWidth, michael@0: int32_t inHeight, michael@0: nsIScreen** outScreen) michael@0: { michael@0: return GetPrimaryScreen(outScreen); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreenManager::ScreenForNativeWidget(void* aWidget, michael@0: nsIScreen** outScreen) michael@0: { michael@0: return GetPrimaryScreen(outScreen); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreenManager::GetNumberOfScreens(uint32_t* aNumberOfScreens) michael@0: { michael@0: *aNumberOfScreens = 1; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: PuppetScreenManager::GetSystemDefaultScale(float *aDefaultScale) michael@0: { michael@0: *aDefaultScale = 1.0f; michael@0: return NS_OK; michael@0: } michael@0: michael@0: } // namespace widget michael@0: } // namespace mozilla