1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/widget/xpwidgets/PuppetWidget.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,908 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: sw=2 ts=8 et : 1.6 + */ 1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#include "base/basictypes.h" 1.12 + 1.13 +#include "ClientLayerManager.h" 1.14 +#include "gfxPlatform.h" 1.15 +#if defined(MOZ_ENABLE_D3D10_LAYER) 1.16 +# include "LayerManagerD3D10.h" 1.17 +#endif 1.18 +#include "mozilla/dom/TabChild.h" 1.19 +#include "mozilla/Hal.h" 1.20 +#include "mozilla/IMEStateManager.h" 1.21 +#include "mozilla/layers/CompositorChild.h" 1.22 +#include "mozilla/layers/PLayerTransactionChild.h" 1.23 +#include "mozilla/TextComposition.h" 1.24 +#include "mozilla/TextEvents.h" 1.25 +#include "PuppetWidget.h" 1.26 +#include "nsIWidgetListener.h" 1.27 + 1.28 +using namespace mozilla::dom; 1.29 +using namespace mozilla::hal; 1.30 +using namespace mozilla::gfx; 1.31 +using namespace mozilla::layers; 1.32 +using namespace mozilla::widget; 1.33 + 1.34 +static void 1.35 +InvalidateRegion(nsIWidget* aWidget, const nsIntRegion& aRegion) 1.36 +{ 1.37 + nsIntRegionRectIterator it(aRegion); 1.38 + while(const nsIntRect* r = it.Next()) { 1.39 + aWidget->Invalidate(*r); 1.40 + } 1.41 +} 1.42 + 1.43 +/*static*/ already_AddRefed<nsIWidget> 1.44 +nsIWidget::CreatePuppetWidget(TabChild* aTabChild) 1.45 +{ 1.46 + NS_ABORT_IF_FALSE(!aTabChild || nsIWidget::UsePuppetWidgets(), 1.47 + "PuppetWidgets not allowed in this configuration"); 1.48 + 1.49 + nsCOMPtr<nsIWidget> widget = new PuppetWidget(aTabChild); 1.50 + return widget.forget(); 1.51 +} 1.52 + 1.53 +namespace mozilla { 1.54 +namespace widget { 1.55 + 1.56 +static bool 1.57 +IsPopup(const nsWidgetInitData* aInitData) 1.58 +{ 1.59 + return aInitData && aInitData->mWindowType == eWindowType_popup; 1.60 +} 1.61 + 1.62 +static bool 1.63 +MightNeedIMEFocus(const nsWidgetInitData* aInitData) 1.64 +{ 1.65 + // In the puppet-widget world, popup widgets are just dummies and 1.66 + // shouldn't try to mess with IME state. 1.67 +#ifdef MOZ_CROSS_PROCESS_IME 1.68 + return !IsPopup(aInitData); 1.69 +#else 1.70 + return false; 1.71 +#endif 1.72 +} 1.73 + 1.74 + 1.75 +// Arbitrary, fungible. 1.76 +const size_t PuppetWidget::kMaxDimension = 4000; 1.77 + 1.78 +NS_IMPL_ISUPPORTS_INHERITED(PuppetWidget, nsBaseWidget, 1.79 + nsISupportsWeakReference) 1.80 + 1.81 +PuppetWidget::PuppetWidget(TabChild* aTabChild) 1.82 + : mTabChild(aTabChild) 1.83 + , mDPI(-1) 1.84 + , mDefaultScale(-1) 1.85 + , mNativeKeyCommandsValid(false) 1.86 +{ 1.87 + MOZ_COUNT_CTOR(PuppetWidget); 1.88 + 1.89 + mSingleLineCommands.SetCapacity(4); 1.90 + mMultiLineCommands.SetCapacity(4); 1.91 + mRichTextCommands.SetCapacity(4); 1.92 +} 1.93 + 1.94 +PuppetWidget::~PuppetWidget() 1.95 +{ 1.96 + MOZ_COUNT_DTOR(PuppetWidget); 1.97 +} 1.98 + 1.99 +NS_IMETHODIMP 1.100 +PuppetWidget::Create(nsIWidget *aParent, 1.101 + nsNativeWidget aNativeParent, 1.102 + const nsIntRect &aRect, 1.103 + nsDeviceContext *aContext, 1.104 + nsWidgetInitData *aInitData) 1.105 +{ 1.106 + NS_ABORT_IF_FALSE(!aNativeParent, "got a non-Puppet native parent"); 1.107 + 1.108 + BaseCreate(nullptr, aRect, aContext, aInitData); 1.109 + 1.110 + mBounds = aRect; 1.111 + mEnabled = true; 1.112 + mVisible = true; 1.113 + 1.114 + mSurface = gfxPlatform::GetPlatform() 1.115 + ->CreateOffscreenSurface(IntSize(1, 1), 1.116 + gfxASurface::ContentFromFormat(gfxImageFormat::ARGB32)); 1.117 + 1.118 + mIMEComposing = false; 1.119 + mNeedIMEStateInit = MightNeedIMEFocus(aInitData); 1.120 + 1.121 + PuppetWidget* parent = static_cast<PuppetWidget*>(aParent); 1.122 + if (parent) { 1.123 + parent->SetChild(this); 1.124 + mLayerManager = parent->GetLayerManager(); 1.125 + } 1.126 + else { 1.127 + Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false); 1.128 + } 1.129 + 1.130 + return NS_OK; 1.131 +} 1.132 + 1.133 +void 1.134 +PuppetWidget::InitIMEState() 1.135 +{ 1.136 + MOZ_ASSERT(mTabChild); 1.137 + if (mNeedIMEStateInit) { 1.138 + uint32_t chromeSeqno; 1.139 + mTabChild->SendNotifyIMEFocus(false, &mIMEPreferenceOfParent, &chromeSeqno); 1.140 + mIMELastBlurSeqno = mIMELastReceivedSeqno = chromeSeqno; 1.141 + mNeedIMEStateInit = false; 1.142 + } 1.143 +} 1.144 + 1.145 +already_AddRefed<nsIWidget> 1.146 +PuppetWidget::CreateChild(const nsIntRect &aRect, 1.147 + nsDeviceContext *aContext, 1.148 + nsWidgetInitData *aInitData, 1.149 + bool aForceUseIWidgetParent) 1.150 +{ 1.151 + bool isPopup = IsPopup(aInitData); 1.152 + nsCOMPtr<nsIWidget> widget = nsIWidget::CreatePuppetWidget(mTabChild); 1.153 + return ((widget && 1.154 + NS_SUCCEEDED(widget->Create(isPopup ? nullptr: this, nullptr, aRect, 1.155 + aContext, aInitData))) ? 1.156 + widget.forget() : nullptr); 1.157 +} 1.158 + 1.159 +NS_IMETHODIMP 1.160 +PuppetWidget::Destroy() 1.161 +{ 1.162 + Base::OnDestroy(); 1.163 + Base::Destroy(); 1.164 + mPaintTask.Revoke(); 1.165 + mChild = nullptr; 1.166 + if (mLayerManager) { 1.167 + mLayerManager->Destroy(); 1.168 + } 1.169 + mLayerManager = nullptr; 1.170 + mTabChild = nullptr; 1.171 + return NS_OK; 1.172 +} 1.173 + 1.174 +NS_IMETHODIMP 1.175 +PuppetWidget::Show(bool aState) 1.176 +{ 1.177 + NS_ASSERTION(mEnabled, 1.178 + "does it make sense to Show()/Hide() a disabled widget?"); 1.179 + 1.180 + bool wasVisible = mVisible; 1.181 + mVisible = aState; 1.182 + 1.183 + if (mChild) { 1.184 + mChild->mVisible = aState; 1.185 + } 1.186 + 1.187 + if (!mVisible && mLayerManager) { 1.188 + mLayerManager->ClearCachedResources(); 1.189 + } 1.190 + 1.191 + if (!wasVisible && mVisible) { 1.192 + Resize(mBounds.width, mBounds.height, false); 1.193 + Invalidate(mBounds); 1.194 + } 1.195 + 1.196 + return NS_OK; 1.197 +} 1.198 + 1.199 +NS_IMETHODIMP 1.200 +PuppetWidget::Resize(double aWidth, 1.201 + double aHeight, 1.202 + bool aRepaint) 1.203 +{ 1.204 + nsIntRect oldBounds = mBounds; 1.205 + mBounds.SizeTo(nsIntSize(NSToIntRound(aWidth), NSToIntRound(aHeight))); 1.206 + 1.207 + if (mChild) { 1.208 + return mChild->Resize(aWidth, aHeight, aRepaint); 1.209 + } 1.210 + 1.211 + // XXX: roc says that |aRepaint| dictates whether or not to 1.212 + // invalidate the expanded area 1.213 + if (oldBounds.Size() < mBounds.Size() && aRepaint) { 1.214 + nsIntRegion dirty(mBounds); 1.215 + dirty.Sub(dirty, oldBounds); 1.216 + InvalidateRegion(this, dirty); 1.217 + } 1.218 + 1.219 + if (!oldBounds.IsEqualEdges(mBounds) && mAttachedWidgetListener) { 1.220 + mAttachedWidgetListener->WindowResized(this, mBounds.width, mBounds.height); 1.221 + } 1.222 + 1.223 + return NS_OK; 1.224 +} 1.225 + 1.226 +NS_IMETHODIMP 1.227 +PuppetWidget::SetFocus(bool aRaise) 1.228 +{ 1.229 + // XXX/cjones: someone who knows about event handling needs to 1.230 + // decide how this should work. 1.231 + return NS_OK; 1.232 +} 1.233 + 1.234 +NS_IMETHODIMP 1.235 +PuppetWidget::Invalidate(const nsIntRect& aRect) 1.236 +{ 1.237 +#ifdef DEBUG 1.238 + debug_DumpInvalidate(stderr, this, &aRect, 1.239 + nsAutoCString("PuppetWidget"), 0); 1.240 +#endif 1.241 + 1.242 + if (mChild) { 1.243 + return mChild->Invalidate(aRect); 1.244 + } 1.245 + 1.246 + mDirtyRegion.Or(mDirtyRegion, aRect); 1.247 + 1.248 + if (!mDirtyRegion.IsEmpty() && !mPaintTask.IsPending()) { 1.249 + mPaintTask = new PaintTask(this); 1.250 + return NS_DispatchToCurrentThread(mPaintTask.get()); 1.251 + } 1.252 + 1.253 + return NS_OK; 1.254 +} 1.255 + 1.256 +void 1.257 +PuppetWidget::InitEvent(WidgetGUIEvent& event, nsIntPoint* aPoint) 1.258 +{ 1.259 + if (nullptr == aPoint) { 1.260 + event.refPoint.x = 0; 1.261 + event.refPoint.y = 0; 1.262 + } 1.263 + else { 1.264 + // use the point override if provided 1.265 + event.refPoint.x = aPoint->x; 1.266 + event.refPoint.y = aPoint->y; 1.267 + } 1.268 + event.time = PR_Now() / 1000; 1.269 +} 1.270 + 1.271 +NS_IMETHODIMP 1.272 +PuppetWidget::DispatchEvent(WidgetGUIEvent* event, nsEventStatus& aStatus) 1.273 +{ 1.274 +#ifdef DEBUG 1.275 + debug_DumpEvent(stdout, event->widget, event, 1.276 + nsAutoCString("PuppetWidget"), 0); 1.277 +#endif 1.278 + 1.279 + NS_ABORT_IF_FALSE(!mChild || mChild->mWindowType == eWindowType_popup, 1.280 + "Unexpected event dispatch!"); 1.281 + 1.282 + AutoCacheNativeKeyCommands autoCache(this); 1.283 + if (event->mFlags.mIsSynthesizedForTests && !mNativeKeyCommandsValid) { 1.284 + WidgetKeyboardEvent* keyEvent = event->AsKeyboardEvent(); 1.285 + if (keyEvent) { 1.286 + mTabChild->RequestNativeKeyBindings(&autoCache, keyEvent); 1.287 + } 1.288 + } 1.289 + 1.290 + aStatus = nsEventStatus_eIgnore; 1.291 + 1.292 + if (event->message == NS_COMPOSITION_START) { 1.293 + mIMEComposing = true; 1.294 + } 1.295 + uint32_t seqno = kLatestSeqno; 1.296 + switch (event->eventStructType) { 1.297 + case NS_COMPOSITION_EVENT: 1.298 + seqno = event->AsCompositionEvent()->mSeqno; 1.299 + break; 1.300 + case NS_TEXT_EVENT: 1.301 + seqno = event->AsTextEvent()->mSeqno; 1.302 + break; 1.303 + case NS_SELECTION_EVENT: 1.304 + seqno = event->AsSelectionEvent()->mSeqno; 1.305 + break; 1.306 + default: 1.307 + break; 1.308 + } 1.309 + if (seqno != kLatestSeqno) { 1.310 + mIMELastReceivedSeqno = seqno; 1.311 + if (mIMELastReceivedSeqno < mIMELastBlurSeqno) { 1.312 + return NS_OK; 1.313 + } 1.314 + } 1.315 + 1.316 + if (mAttachedWidgetListener) { 1.317 + aStatus = mAttachedWidgetListener->HandleEvent(event, mUseAttachedEvents); 1.318 + } 1.319 + 1.320 + if (event->message == NS_COMPOSITION_END) { 1.321 + mIMEComposing = false; 1.322 + } 1.323 + 1.324 + return NS_OK; 1.325 +} 1.326 + 1.327 + 1.328 +NS_IMETHODIMP_(bool) 1.329 +PuppetWidget::ExecuteNativeKeyBinding(NativeKeyBindingsType aType, 1.330 + const mozilla::WidgetKeyboardEvent& aEvent, 1.331 + DoCommandCallback aCallback, 1.332 + void* aCallbackData) 1.333 +{ 1.334 + // B2G doesn't have native key bindings. 1.335 +#ifdef MOZ_B2G 1.336 + return false; 1.337 +#else // #ifdef MOZ_B2G 1.338 + MOZ_ASSERT(mNativeKeyCommandsValid); 1.339 + 1.340 + nsTArray<mozilla::CommandInt>& commands = mSingleLineCommands; 1.341 + switch (aType) { 1.342 + case nsIWidget::NativeKeyBindingsForSingleLineEditor: 1.343 + commands = mSingleLineCommands; 1.344 + break; 1.345 + case nsIWidget::NativeKeyBindingsForMultiLineEditor: 1.346 + commands = mMultiLineCommands; 1.347 + break; 1.348 + case nsIWidget::NativeKeyBindingsForRichTextEditor: 1.349 + commands = mRichTextCommands; 1.350 + break; 1.351 + } 1.352 + 1.353 + if (commands.IsEmpty()) { 1.354 + return false; 1.355 + } 1.356 + 1.357 + for (uint32_t i = 0; i < commands.Length(); i++) { 1.358 + aCallback(static_cast<mozilla::Command>(commands[i]), aCallbackData); 1.359 + } 1.360 + return true; 1.361 +#endif 1.362 +} 1.363 + 1.364 +LayerManager* 1.365 +PuppetWidget::GetLayerManager(PLayerTransactionChild* aShadowManager, 1.366 + LayersBackend aBackendHint, 1.367 + LayerManagerPersistence aPersistence, 1.368 + bool* aAllowRetaining) 1.369 +{ 1.370 + if (!mLayerManager) { 1.371 + // The backend hint is a temporary placeholder until Azure, when 1.372 + // all content-process layer managers will be BasicLayerManagers. 1.373 +#if defined(MOZ_ENABLE_D3D10_LAYER) 1.374 + if (mozilla::layers::LayersBackend::LAYERS_D3D10 == aBackendHint) { 1.375 + nsRefPtr<LayerManagerD3D10> m = new LayerManagerD3D10(this); 1.376 + m->AsShadowForwarder()->SetShadowManager(aShadowManager); 1.377 + if (m->Initialize()) { 1.378 + mLayerManager = m; 1.379 + } 1.380 + } 1.381 +#endif 1.382 + if (!mLayerManager) { 1.383 + mLayerManager = new ClientLayerManager(this); 1.384 + } 1.385 + } 1.386 + ShadowLayerForwarder* lf = mLayerManager->AsShadowForwarder(); 1.387 + if (!lf->HasShadowManager() && aShadowManager) { 1.388 + lf->SetShadowManager(aShadowManager); 1.389 + } 1.390 + if (aAllowRetaining) { 1.391 + *aAllowRetaining = true; 1.392 + } 1.393 + return mLayerManager; 1.394 +} 1.395 + 1.396 +gfxASurface* 1.397 +PuppetWidget::GetThebesSurface() 1.398 +{ 1.399 + return mSurface; 1.400 +} 1.401 + 1.402 +nsresult 1.403 +PuppetWidget::IMEEndComposition(bool aCancel) 1.404 +{ 1.405 +#ifndef MOZ_CROSS_PROCESS_IME 1.406 + return NS_OK; 1.407 +#endif 1.408 + 1.409 + nsEventStatus status; 1.410 + WidgetTextEvent textEvent(true, NS_TEXT_TEXT, this); 1.411 + InitEvent(textEvent, nullptr); 1.412 + textEvent.mSeqno = mIMELastReceivedSeqno; 1.413 + // SendEndIMEComposition is always called since ResetInputState 1.414 + // should always be called even if we aren't composing something. 1.415 + if (!mTabChild || 1.416 + !mTabChild->SendEndIMEComposition(aCancel, &textEvent.theText)) { 1.417 + return NS_ERROR_FAILURE; 1.418 + } 1.419 + 1.420 + if (!mIMEComposing) 1.421 + return NS_OK; 1.422 + 1.423 + DispatchEvent(&textEvent, status); 1.424 + 1.425 + WidgetCompositionEvent compEvent(true, NS_COMPOSITION_END, this); 1.426 + InitEvent(compEvent, nullptr); 1.427 + compEvent.mSeqno = mIMELastReceivedSeqno; 1.428 + DispatchEvent(&compEvent, status); 1.429 + return NS_OK; 1.430 +} 1.431 + 1.432 +NS_IMETHODIMP 1.433 +PuppetWidget::NotifyIME(const IMENotification& aIMENotification) 1.434 +{ 1.435 + switch (aIMENotification.mMessage) { 1.436 + case NOTIFY_IME_OF_CURSOR_POS_CHANGED: 1.437 + case REQUEST_TO_COMMIT_COMPOSITION: 1.438 + return IMEEndComposition(false); 1.439 + case REQUEST_TO_CANCEL_COMPOSITION: 1.440 + return IMEEndComposition(true); 1.441 + case NOTIFY_IME_OF_FOCUS: 1.442 + return NotifyIMEOfFocusChange(true); 1.443 + case NOTIFY_IME_OF_BLUR: 1.444 + return NotifyIMEOfFocusChange(false); 1.445 + case NOTIFY_IME_OF_SELECTION_CHANGE: 1.446 + return NotifyIMEOfSelectionChange(aIMENotification); 1.447 + case NOTIFY_IME_OF_TEXT_CHANGE: 1.448 + return NotifyIMEOfTextChange(aIMENotification); 1.449 + case NOTIFY_IME_OF_COMPOSITION_UPDATE: 1.450 + return NotifyIMEOfUpdateComposition(); 1.451 + default: 1.452 + return NS_ERROR_NOT_IMPLEMENTED; 1.453 + } 1.454 +} 1.455 + 1.456 +NS_IMETHODIMP_(void) 1.457 +PuppetWidget::SetInputContext(const InputContext& aContext, 1.458 + const InputContextAction& aAction) 1.459 +{ 1.460 +#ifndef MOZ_CROSS_PROCESS_IME 1.461 + return; 1.462 +#endif 1.463 + 1.464 + if (!mTabChild) { 1.465 + return; 1.466 + } 1.467 + mTabChild->SendSetInputContext( 1.468 + static_cast<int32_t>(aContext.mIMEState.mEnabled), 1.469 + static_cast<int32_t>(aContext.mIMEState.mOpen), 1.470 + aContext.mHTMLInputType, 1.471 + aContext.mHTMLInputInputmode, 1.472 + aContext.mActionHint, 1.473 + static_cast<int32_t>(aAction.mCause), 1.474 + static_cast<int32_t>(aAction.mFocusChange)); 1.475 +} 1.476 + 1.477 +NS_IMETHODIMP_(InputContext) 1.478 +PuppetWidget::GetInputContext() 1.479 +{ 1.480 +#ifndef MOZ_CROSS_PROCESS_IME 1.481 + return InputContext(); 1.482 +#endif 1.483 + 1.484 + InputContext context; 1.485 + if (mTabChild) { 1.486 + int32_t enabled, open; 1.487 + intptr_t nativeIMEContext; 1.488 + mTabChild->SendGetInputContext(&enabled, &open, &nativeIMEContext); 1.489 + context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(enabled); 1.490 + context.mIMEState.mOpen = static_cast<IMEState::Open>(open); 1.491 + context.mNativeIMEContext = reinterpret_cast<void*>(nativeIMEContext); 1.492 + } 1.493 + return context; 1.494 +} 1.495 + 1.496 +nsresult 1.497 +PuppetWidget::NotifyIMEOfFocusChange(bool aFocus) 1.498 +{ 1.499 +#ifndef MOZ_CROSS_PROCESS_IME 1.500 + return NS_OK; 1.501 +#endif 1.502 + 1.503 + if (!mTabChild) 1.504 + return NS_ERROR_FAILURE; 1.505 + 1.506 + if (aFocus) { 1.507 + nsEventStatus status; 1.508 + WidgetQueryContentEvent queryEvent(true, NS_QUERY_TEXT_CONTENT, this); 1.509 + InitEvent(queryEvent, nullptr); 1.510 + // Query entire content 1.511 + queryEvent.InitForQueryTextContent(0, UINT32_MAX); 1.512 + DispatchEvent(&queryEvent, status); 1.513 + 1.514 + if (queryEvent.mSucceeded) { 1.515 + mTabChild->SendNotifyIMETextHint(queryEvent.mReply.mString); 1.516 + } 1.517 + } else { 1.518 + // Might not have been committed composition yet 1.519 + IMEEndComposition(false); 1.520 + } 1.521 + 1.522 + uint32_t chromeSeqno; 1.523 + mIMEPreferenceOfParent = nsIMEUpdatePreference(); 1.524 + if (!mTabChild->SendNotifyIMEFocus(aFocus, &mIMEPreferenceOfParent, 1.525 + &chromeSeqno)) { 1.526 + return NS_ERROR_FAILURE; 1.527 + } 1.528 + 1.529 + if (aFocus) { 1.530 + IMENotification notification(NOTIFY_IME_OF_SELECTION_CHANGE); 1.531 + notification.mSelectionChangeData.mCausedByComposition = false; 1.532 + NotifyIMEOfSelectionChange(notification); // Update selection 1.533 + } else { 1.534 + mIMELastBlurSeqno = chromeSeqno; 1.535 + } 1.536 + return NS_OK; 1.537 +} 1.538 + 1.539 +nsresult 1.540 +PuppetWidget::NotifyIMEOfUpdateComposition() 1.541 +{ 1.542 +#ifndef MOZ_CROSS_PROCESS_IME 1.543 + return NS_OK; 1.544 +#endif 1.545 + 1.546 + NS_ENSURE_TRUE(mTabChild, NS_ERROR_FAILURE); 1.547 + 1.548 + nsRefPtr<TextComposition> textComposition = 1.549 + IMEStateManager::GetTextCompositionFor(this); 1.550 + NS_ENSURE_TRUE(textComposition, NS_ERROR_FAILURE); 1.551 + 1.552 + nsEventStatus status; 1.553 + uint32_t offset = textComposition->OffsetOfTargetClause(); 1.554 + WidgetQueryContentEvent textRect(true, NS_QUERY_TEXT_RECT, this); 1.555 + InitEvent(textRect, nullptr); 1.556 + textRect.InitForQueryTextRect(offset, 1); 1.557 + DispatchEvent(&textRect, status); 1.558 + NS_ENSURE_TRUE(textRect.mSucceeded, NS_ERROR_FAILURE); 1.559 + 1.560 + WidgetQueryContentEvent caretRect(true, NS_QUERY_CARET_RECT, this); 1.561 + InitEvent(caretRect, nullptr); 1.562 + caretRect.InitForQueryCaretRect(offset); 1.563 + DispatchEvent(&caretRect, status); 1.564 + NS_ENSURE_TRUE(caretRect.mSucceeded, NS_ERROR_FAILURE); 1.565 + 1.566 + mTabChild->SendNotifyIMESelectedCompositionRect(offset, 1.567 + textRect.mReply.mRect, 1.568 + caretRect.mReply.mRect); 1.569 + return NS_OK; 1.570 +} 1.571 + 1.572 +nsIMEUpdatePreference 1.573 +PuppetWidget::GetIMEUpdatePreference() 1.574 +{ 1.575 +#ifdef MOZ_CROSS_PROCESS_IME 1.576 + // e10s requires IME information cache into TabParent 1.577 + return nsIMEUpdatePreference(mIMEPreferenceOfParent.mWantUpdates | 1.578 + nsIMEUpdatePreference::NOTIFY_SELECTION_CHANGE | 1.579 + nsIMEUpdatePreference::NOTIFY_TEXT_CHANGE); 1.580 +#else 1.581 + // B2G doesn't handle IME as widget-level. 1.582 + return nsIMEUpdatePreference(); 1.583 +#endif 1.584 +} 1.585 + 1.586 +nsresult 1.587 +PuppetWidget::NotifyIMEOfTextChange(const IMENotification& aIMENotification) 1.588 +{ 1.589 + MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_TEXT_CHANGE, 1.590 + "Passed wrong notification"); 1.591 + 1.592 +#ifndef MOZ_CROSS_PROCESS_IME 1.593 + return NS_OK; 1.594 +#endif 1.595 + 1.596 + if (!mTabChild) 1.597 + return NS_ERROR_FAILURE; 1.598 + 1.599 + nsEventStatus status; 1.600 + WidgetQueryContentEvent queryEvent(true, NS_QUERY_TEXT_CONTENT, this); 1.601 + InitEvent(queryEvent, nullptr); 1.602 + queryEvent.InitForQueryTextContent(0, UINT32_MAX); 1.603 + DispatchEvent(&queryEvent, status); 1.604 + 1.605 + if (queryEvent.mSucceeded) { 1.606 + mTabChild->SendNotifyIMETextHint(queryEvent.mReply.mString); 1.607 + } 1.608 + 1.609 + // TabParent doesn't this this to cache. we don't send the notification 1.610 + // if parent process doesn't request NOTIFY_TEXT_CHANGE. 1.611 + if (mIMEPreferenceOfParent.WantTextChange() && 1.612 + (mIMEPreferenceOfParent.WantChangesCausedByComposition() || 1.613 + !aIMENotification.mTextChangeData.mCausedByComposition)) { 1.614 + mTabChild->SendNotifyIMETextChange( 1.615 + aIMENotification.mTextChangeData.mStartOffset, 1.616 + aIMENotification.mTextChangeData.mOldEndOffset, 1.617 + aIMENotification.mTextChangeData.mNewEndOffset, 1.618 + aIMENotification.mTextChangeData.mCausedByComposition); 1.619 + } 1.620 + return NS_OK; 1.621 +} 1.622 + 1.623 +nsresult 1.624 +PuppetWidget::NotifyIMEOfSelectionChange( 1.625 + const IMENotification& aIMENotification) 1.626 +{ 1.627 + MOZ_ASSERT(aIMENotification.mMessage == NOTIFY_IME_OF_SELECTION_CHANGE, 1.628 + "Passed wrong notification"); 1.629 + 1.630 +#ifndef MOZ_CROSS_PROCESS_IME 1.631 + return NS_OK; 1.632 +#endif 1.633 + 1.634 + if (!mTabChild) 1.635 + return NS_ERROR_FAILURE; 1.636 + 1.637 + nsEventStatus status; 1.638 + WidgetQueryContentEvent queryEvent(true, NS_QUERY_SELECTED_TEXT, this); 1.639 + InitEvent(queryEvent, nullptr); 1.640 + DispatchEvent(&queryEvent, status); 1.641 + 1.642 + if (queryEvent.mSucceeded) { 1.643 + mTabChild->SendNotifyIMESelection( 1.644 + mIMELastReceivedSeqno, 1.645 + queryEvent.GetSelectionStart(), 1.646 + queryEvent.GetSelectionEnd(), 1.647 + aIMENotification.mSelectionChangeData.mCausedByComposition); 1.648 + } 1.649 + return NS_OK; 1.650 +} 1.651 + 1.652 +NS_IMETHODIMP 1.653 +PuppetWidget::SetCursor(nsCursor aCursor) 1.654 +{ 1.655 + if (mCursor == aCursor) { 1.656 + return NS_OK; 1.657 + } 1.658 + 1.659 + if (mTabChild && !mTabChild->SendSetCursor(aCursor)) { 1.660 + return NS_ERROR_FAILURE; 1.661 + } 1.662 + 1.663 + mCursor = aCursor; 1.664 + 1.665 + return NS_OK; 1.666 +} 1.667 + 1.668 +nsresult 1.669 +PuppetWidget::Paint() 1.670 +{ 1.671 + NS_ABORT_IF_FALSE(!mDirtyRegion.IsEmpty(), "paint event logic messed up"); 1.672 + 1.673 + if (!mAttachedWidgetListener) 1.674 + return NS_OK; 1.675 + 1.676 + nsIntRegion region = mDirtyRegion; 1.677 + 1.678 + // reset repaint tracking 1.679 + mDirtyRegion.SetEmpty(); 1.680 + mPaintTask.Revoke(); 1.681 + 1.682 + mAttachedWidgetListener->WillPaintWindow(this); 1.683 + 1.684 + if (mAttachedWidgetListener) { 1.685 +#ifdef DEBUG 1.686 + debug_DumpPaintEvent(stderr, this, region, 1.687 + nsAutoCString("PuppetWidget"), 0); 1.688 +#endif 1.689 + 1.690 + if (mozilla::layers::LayersBackend::LAYERS_D3D10 == mLayerManager->GetBackendType()) { 1.691 + mAttachedWidgetListener->PaintWindow(this, region); 1.692 + } else if (mozilla::layers::LayersBackend::LAYERS_CLIENT == mLayerManager->GetBackendType()) { 1.693 + // Do nothing, the compositor will handle drawing 1.694 + if (mTabChild) { 1.695 + mTabChild->NotifyPainted(); 1.696 + } 1.697 + } else { 1.698 + nsRefPtr<gfxContext> ctx = new gfxContext(mSurface); 1.699 + ctx->Rectangle(gfxRect(0,0,0,0)); 1.700 + ctx->Clip(); 1.701 + AutoLayerManagerSetup setupLayerManager(this, ctx, 1.702 + BufferMode::BUFFER_NONE); 1.703 + mAttachedWidgetListener->PaintWindow(this, region); 1.704 + if (mTabChild) { 1.705 + mTabChild->NotifyPainted(); 1.706 + } 1.707 + } 1.708 + } 1.709 + 1.710 + if (mAttachedWidgetListener) { 1.711 + mAttachedWidgetListener->DidPaintWindow(); 1.712 + } 1.713 + 1.714 + return NS_OK; 1.715 +} 1.716 + 1.717 +void 1.718 +PuppetWidget::SetChild(PuppetWidget* aChild) 1.719 +{ 1.720 + NS_ABORT_IF_FALSE(this != aChild, "can't parent a widget to itself"); 1.721 + NS_ABORT_IF_FALSE(!aChild->mChild, 1.722 + "fake widget 'hierarchy' only expected to have one level"); 1.723 + 1.724 + mChild = aChild; 1.725 +} 1.726 + 1.727 +NS_IMETHODIMP 1.728 +PuppetWidget::PaintTask::Run() 1.729 +{ 1.730 + if (mWidget) { 1.731 + mWidget->Paint(); 1.732 + } 1.733 + return NS_OK; 1.734 +} 1.735 + 1.736 +bool 1.737 +PuppetWidget::NeedsPaint() 1.738 +{ 1.739 + return mVisible; 1.740 +} 1.741 + 1.742 +float 1.743 +PuppetWidget::GetDPI() 1.744 +{ 1.745 + if (mDPI < 0) { 1.746 + if (mTabChild) { 1.747 + mTabChild->GetDPI(&mDPI); 1.748 + } else { 1.749 + mDPI = 96.0; 1.750 + } 1.751 + } 1.752 + 1.753 + return mDPI; 1.754 +} 1.755 + 1.756 +double 1.757 +PuppetWidget::GetDefaultScaleInternal() 1.758 +{ 1.759 + if (mDefaultScale < 0) { 1.760 + if (mTabChild) { 1.761 + mTabChild->GetDefaultScale(&mDefaultScale); 1.762 + } else { 1.763 + mDefaultScale = 1; 1.764 + } 1.765 + } 1.766 + 1.767 + return mDefaultScale; 1.768 +} 1.769 + 1.770 +void* 1.771 +PuppetWidget::GetNativeData(uint32_t aDataType) 1.772 +{ 1.773 + switch (aDataType) { 1.774 + case NS_NATIVE_SHAREABLE_WINDOW: { 1.775 + NS_ABORT_IF_FALSE(mTabChild, "Need TabChild to get the nativeWindow from!"); 1.776 + mozilla::WindowsHandle nativeData = 0; 1.777 + if (mTabChild) { 1.778 + mTabChild->SendGetWidgetNativeData(&nativeData); 1.779 + } 1.780 + return (void*)nativeData; 1.781 + } 1.782 + case NS_NATIVE_WINDOW: 1.783 + case NS_NATIVE_DISPLAY: 1.784 + case NS_NATIVE_PLUGIN_PORT: 1.785 + case NS_NATIVE_GRAPHIC: 1.786 + case NS_NATIVE_SHELLWIDGET: 1.787 + case NS_NATIVE_WIDGET: 1.788 + NS_WARNING("nsWindow::GetNativeData not implemented for this type"); 1.789 + break; 1.790 + default: 1.791 + NS_WARNING("nsWindow::GetNativeData called with bad value"); 1.792 + break; 1.793 + } 1.794 + return nullptr; 1.795 +} 1.796 + 1.797 +PuppetScreen::PuppetScreen(void *nativeScreen) 1.798 +{ 1.799 +} 1.800 + 1.801 +PuppetScreen::~PuppetScreen() 1.802 +{ 1.803 +} 1.804 + 1.805 +static ScreenConfiguration 1.806 +ScreenConfig() 1.807 +{ 1.808 + ScreenConfiguration config; 1.809 + hal::GetCurrentScreenConfiguration(&config); 1.810 + return config; 1.811 +} 1.812 + 1.813 +NS_IMETHODIMP 1.814 +PuppetScreen::GetRect(int32_t *outLeft, int32_t *outTop, 1.815 + int32_t *outWidth, int32_t *outHeight) 1.816 +{ 1.817 + nsIntRect r = ScreenConfig().rect(); 1.818 + *outLeft = r.x; 1.819 + *outTop = r.y; 1.820 + *outWidth = r.width; 1.821 + *outHeight = r.height; 1.822 + return NS_OK; 1.823 +} 1.824 + 1.825 +NS_IMETHODIMP 1.826 +PuppetScreen::GetAvailRect(int32_t *outLeft, int32_t *outTop, 1.827 + int32_t *outWidth, int32_t *outHeight) 1.828 +{ 1.829 + return GetRect(outLeft, outTop, outWidth, outHeight); 1.830 +} 1.831 + 1.832 + 1.833 +NS_IMETHODIMP 1.834 +PuppetScreen::GetPixelDepth(int32_t *aPixelDepth) 1.835 +{ 1.836 + *aPixelDepth = ScreenConfig().pixelDepth(); 1.837 + return NS_OK; 1.838 +} 1.839 + 1.840 +NS_IMETHODIMP 1.841 +PuppetScreen::GetColorDepth(int32_t *aColorDepth) 1.842 +{ 1.843 + *aColorDepth = ScreenConfig().colorDepth(); 1.844 + return NS_OK; 1.845 +} 1.846 + 1.847 +NS_IMETHODIMP 1.848 +PuppetScreen::GetRotation(uint32_t* aRotation) 1.849 +{ 1.850 + 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."); 1.851 + return NS_ERROR_NOT_AVAILABLE; 1.852 +} 1.853 + 1.854 +NS_IMETHODIMP 1.855 +PuppetScreen::SetRotation(uint32_t aRotation) 1.856 +{ 1.857 + 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."); 1.858 + return NS_ERROR_NOT_AVAILABLE; 1.859 +} 1.860 + 1.861 +NS_IMPL_ISUPPORTS(PuppetScreenManager, nsIScreenManager) 1.862 + 1.863 +PuppetScreenManager::PuppetScreenManager() 1.864 +{ 1.865 + mOneScreen = new PuppetScreen(nullptr); 1.866 +} 1.867 + 1.868 +PuppetScreenManager::~PuppetScreenManager() 1.869 +{ 1.870 +} 1.871 + 1.872 +NS_IMETHODIMP 1.873 +PuppetScreenManager::GetPrimaryScreen(nsIScreen** outScreen) 1.874 +{ 1.875 + NS_IF_ADDREF(*outScreen = mOneScreen.get()); 1.876 + return NS_OK; 1.877 +} 1.878 + 1.879 +NS_IMETHODIMP 1.880 +PuppetScreenManager::ScreenForRect(int32_t inLeft, 1.881 + int32_t inTop, 1.882 + int32_t inWidth, 1.883 + int32_t inHeight, 1.884 + nsIScreen** outScreen) 1.885 +{ 1.886 + return GetPrimaryScreen(outScreen); 1.887 +} 1.888 + 1.889 +NS_IMETHODIMP 1.890 +PuppetScreenManager::ScreenForNativeWidget(void* aWidget, 1.891 + nsIScreen** outScreen) 1.892 +{ 1.893 + return GetPrimaryScreen(outScreen); 1.894 +} 1.895 + 1.896 +NS_IMETHODIMP 1.897 +PuppetScreenManager::GetNumberOfScreens(uint32_t* aNumberOfScreens) 1.898 +{ 1.899 + *aNumberOfScreens = 1; 1.900 + return NS_OK; 1.901 +} 1.902 + 1.903 +NS_IMETHODIMP 1.904 +PuppetScreenManager::GetSystemDefaultScale(float *aDefaultScale) 1.905 +{ 1.906 + *aDefaultScale = 1.0f; 1.907 + return NS_OK; 1.908 +} 1.909 + 1.910 +} // namespace widget 1.911 +} // namespace mozilla