/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: sw=2 ts=8 et :
*/ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
staticvoid InvalidateRegion(nsIWidget* aWidget, const LayoutDeviceIntRegion& aRegion) { for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
aWidget->Invalidate(iter.Get());
}
}
/*static*/
already_AddRefed<nsIWidget> nsIWidget::CreatePuppetWidget(
BrowserChild* aBrowserChild) {
MOZ_ASSERT(!aBrowserChild || nsIWidget::UsePuppetWidgets(), "PuppetWidgets not allowed in this configuration");
nsCOMPtr<nsIWidget> widget = new PuppetWidget(aBrowserChild); return widget.forget();
}
staticbool MightNeedIMEFocus(const widget::InitData* aInitData) { // In the puppet-widget world, popup widgets are just dummies and // shouldn't try to mess with IME state. // // FIXME(emilio): Pretty sure we no longer have puppet popups. #ifdef MOZ_CROSS_PROCESS_IME return !IsPopup(aInitData); #else returnfalse; #endif
}
void PuppetWidget::Show(bool aState) {
NS_ASSERTION(mEnabled, "does it make sense to Show()/Hide() a disabled widget?");
bool wasVisible = mVisible;
mVisible = aState;
if (!wasVisible && mVisible) { // The previously attached widget listener is handy if // we're transitioning from page to page without dropping // layers (since we'll continue to show the old layers // associated with that old widget listener). If the // PuppetWidget was hidden, those layers are dropped, // so the previously attached widget listener is really // of no use anymore (and is actually actively harmful - see // bug 1323586).
mPreviouslyAttachedWidgetListener = nullptr;
Resize(mBounds.Width(), mBounds.Height(), false);
Invalidate(mBounds);
}
}
// XXX: roc says that |aRepaint| dictates whether or not to // invalidate the expanded area if (oldBounds.Size() < mBounds.Size() && aRepaint) {
LayoutDeviceIntRegion dirty(mBounds);
dirty.Sub(dirty, oldBounds);
InvalidateRegion(this, dirty);
}
// call WindowResized() on both the current listener, and possibly // also the previous one if we're in a state where we're drawing that one // because the current one is paint suppressed if (!oldBounds.IsEqualEdges(mBounds) && mAttachedWidgetListener) { if (GetCurrentWidgetListener() &&
GetCurrentWidgetListener() != mAttachedWidgetListener) {
GetCurrentWidgetListener()->WindowResized(this, mBounds.Width(),
mBounds.Height());
}
mAttachedWidgetListener->WindowResized(this, mBounds.Width(),
mBounds.Height());
}
}
if (mBrowserChild && !aRect.IsEmpty() && !mWidgetPaintTask.IsPending()) {
mWidgetPaintTask = new WidgetPaintTask(this);
nsCOMPtr<nsIRunnable> event(mWidgetPaintTask.get());
SchedulerGroup::Dispatch(event.forget());
}
}
mozilla::LayoutDeviceToLayoutDeviceMatrix4x4
PuppetWidget::WidgetToTopLevelWidgetTransform() { if (!GetOwningBrowserChild()) {
NS_WARNING("PuppetWidget without Tab does not have transform information."); return mozilla::LayoutDeviceToLayoutDeviceMatrix4x4();
} return GetOwningBrowserChild()->GetChildToParentConversionMatrix();
}
void PuppetWidget::InitEvent(WidgetGUIEvent& aEvent,
LayoutDeviceIntPoint* aPoint) { if (nullptr == aPoint) {
aEvent.mRefPoint = LayoutDeviceIntPoint(0, 0);
} else { // use the point override if provided
aEvent.mRefPoint = *aPoint;
}
}
MOZ_ASSERT(!aEvent->AsKeyboardEvent() ||
aEvent->mFlags.mIsSynthesizedForTests ||
aEvent->AsKeyboardEvent()->AreAllEditCommandsInitialized(), "Non-sysnthesized keyboard events should have edit commands for " "all types " "before dispatched");
if (aEvent->mClass == eCompositionEventClass) { // If we've already requested to commit/cancel the latest composition, // TextComposition for the old composition has been destroyed. Then, // the DOM tree needs to listen to next eCompositionStart and its // following events. So, until we meet new eCompositionStart, let's // discard all unnecessary composition events here. if (mIgnoreCompositionEvents) { if (aEvent->mMessage != eCompositionStart) {
aStatus = nsEventStatus_eIgnore; return NS_OK;
} // Now, we receive new eCompositionStart. Let's restart to handle // composition in this process.
mIgnoreCompositionEvents = false;
} // Store the latest native IME context of parent process's widget or // TextEventDispatcher if it's in this process.
WidgetCompositionEvent* compositionEvent = aEvent->AsCompositionEvent(); #ifdef DEBUG if (mNativeIMEContext.IsValid() &&
mNativeIMEContext != compositionEvent->mNativeIMEContext) {
RefPtr<TextComposition> composition =
IMEStateManager::GetTextCompositionFor(this);
MOZ_ASSERT(
!composition, "When there is composition caused by old native IME context, " "composition events caused by different native IME context are not " "allowed");
} #endif// #ifdef DEBUG
mNativeIMEContext = compositionEvent->mNativeIMEContext;
mContentCache.OnCompositionEvent(*compositionEvent);
}
// If the event is a composition event or a keyboard event, it should be // dispatched with TextEventDispatcher if we could do that with current // design. However, we cannot do that without big changes and the behavior // is not so complicated for now. Therefore, we should just notify it // of dispatching events and TextEventDispatcher should emulate the state // with events here. if (aEvent->mClass == eCompositionEventClass ||
aEvent->mClass == eKeyboardEventClass) {
TextEventDispatcher* dispatcher = GetTextEventDispatcher(); // However, if the event is being dispatched by the text event dispatcher // or, there is native text event dispatcher listener, that means that // native text input event handler is in this process like on Android, // and the event is not synthesized for tests, the event is coming from // the TextEventDispatcher. In these cases, we shouldn't notify // TextEventDispatcher of dispatching the event. if (!dispatcher->IsDispatchingEvent() &&
!(mNativeTextEventDispatcherListener &&
!aEvent->mFlags.mIsSynthesizedForTests)) {
DebugOnly<nsresult> rv =
dispatcher->BeginInputTransactionFor(aEvent, this);
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv), "The text event dispatcher should always succeed to start input " "transaction for the event");
}
}
aStatus = nsEventStatus_eIgnore;
if (GetCurrentWidgetListener()) {
aStatus =
GetCurrentWidgetListener()->HandleEvent(aEvent, mUseAttachedEvents);
}
WindowRenderer* PuppetWidget::GetWindowRenderer() { if (!mWindowRenderer) { if (XRE_IsParentProcess()) { // On the parent process there is no CompositorBridgeChild which confuses // some layers code, so we use basic layers instead. Note that we create
mWindowRenderer = new FallbackRenderer; return mWindowRenderer;
}
// If we know for sure that the parent side of this BrowserChild is not // connected to the compositor, we don't want to use a "remote" layer // manager like WebRender or Client. Instead we use a Basic one which // can do drawing in this process.
MOZ_ASSERT(!mBrowserChild ||
mBrowserChild->IsLayersConnected() != Some(true));
mWindowRenderer = CreateFallbackRenderer();
}
// Force the old LM to self destruct, otherwise if the reference dangles we // could fail to revoke the most recent transaction. We only want to replace // it if we successfully create its successor because a partially initialized // layer manager is worse than a fully initialized but shutdown layer manager.
DestroyLayerManager();
mWindowRenderer = std::move(lm); returntrue;
}
nsresult PuppetWidget::RequestIMEToCommitComposition(bool aCancel) { if (!mBrowserChild) { return NS_ERROR_FAILURE;
}
MOZ_ASSERT(!Destroyed());
// There must not be composition which is caused by the PuppetWidget instance. if (NS_WARN_IF(!mNativeIMEContext.IsValid())) { return NS_OK;
}
RefPtr<TextComposition> composition =
IMEStateManager::GetTextCompositionFor(this); // This method shouldn't be called when there is no text composition instance. if (NS_WARN_IF(!composition)) { return NS_OK;
}
MOZ_DIAGNOSTIC_ASSERT(
composition->IsRequestingCommitOrCancelComposition(), "Requesting commit or cancel composition should be requested via " "TextComposition instance");
// If the composition wasn't committed synchronously, we need to wait async // composition events for destroying the TextComposition instance. if (!isCommitted) { return NS_OK;
}
// NOTE: PuppetWidget might be destroyed already. return NS_OK;
}
// When this widget caches input context and currently managed by // IMEStateManager, the cache is valid. bool PuppetWidget::HaveValidInputContextCache() const { return (mInputContext.mIMEState.mEnabled != IMEEnabled::Unknown &&
IMEStateManager::GetWidgetForActiveInputContext() == this);
}
nsRefreshDriver* PuppetWidget::GetTopLevelRefreshDriver() const { if (!mBrowserChild) { return nullptr;
}
if (PresShell* presShell = mBrowserChild->GetTopLevelPresShell()) { return presShell->GetRefreshDriver();
}
return nullptr;
}
void PuppetWidget::SetInputContext(const InputContext& aContext, const InputContextAction& aAction) {
mInputContext = aContext; // Any widget instances cannot cache IME open state because IME open state // can be changed by user but native IME may not notify us of changing the // open state on some platforms.
mInputContext.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED; if (!mBrowserChild) { return;
}
mBrowserChild->SendSetInputContext(aContext, aAction);
}
InputContext PuppetWidget::GetInputContext() { // XXX Currently, we don't support retrieving IME open state from child // process.
// If the cache of input context is valid, we can avoid to use synchronous // IPC. if (HaveValidInputContextCache()) { return mInputContext;
}
NS_WARNING("PuppetWidget::GetInputContext() needs to retrieve it with IPC");
// Don't cache InputContext here because this process isn't managing IME // state of the chrome widget. So, we cannot modify mInputContext when // chrome widget is set to new context.
InputContext context; if (mBrowserChild) {
mBrowserChild->SendGetInputContext(&context.mIMEState);
} return context;
}
bool gotFocus = aIMENotification.mMessage == NOTIFY_IME_OF_FOCUS; if (gotFocus) { // When IME gets focus, we should initialize all information of the // content, however, it may fail to get it because the editor may have // already been blurred. if (NS_WARN_IF(!mContentCache.CacheAll(this, &aIMENotification))) { return NS_ERROR_FAILURE;
}
} else { // When IME loses focus, we don't need to store anything.
mContentCache.Clear();
}
// FYI: text change notification is the first notification after // a user operation changes the content. So, we need to modify // the cache as far as possible here.
if (NS_WARN_IF(!mContentCache.CacheText(this, &aIMENotification))) { return NS_ERROR_FAILURE;
}
// BrowserParent doesn't this this to cache. we don't send the notification // if parent process doesn't request NOTIFY_TEXT_CHANGE. if (mIMENotificationRequestsOfParent.WantTextChange()) {
mBrowserChild->SendNotifyIMETextChange(mContentCache, aIMENotification);
} else {
mBrowserChild->SendUpdateContentCache(mContentCache);
} return NS_OK;
}
// Note that selection change must be notified after text change if it occurs. // Therefore, we don't need to query text content again here. if (MOZ_UNLIKELY(!mContentCache.SetSelection( this, aIMENotification.mSelectionChangeData))) { // If there is no text cache yet, caching text will cache selection too. // Therefore, in the case, we don't need to notify IME of selection change // right now. return NS_OK;
}
const int32_t flags =
imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY;
RefPtr<SourceSurface> surface; if (width && height &&
aCursor.mContainer->GetType() == imgIContainer::TYPE_VECTOR) { // For vector images, scale to device pixels.
resolution.ScaleBy(GetDefaultScale().scale);
resolution.ApplyInverseTo(width, height);
surface = aCursor.mContainer->GetFrameAtSize(
{width, height}, imgIContainer::FRAME_CURRENT, flags);
} else { // NOTE(emilio): We get the frame at the full size, ignoring resolution, // because we're going to rasterize it, and we'd effectively lose the // extra pixels if we rasterized to CustomCursorSize.
surface =
aCursor.mContainer->GetFrame(imgIContainer::FRAME_CURRENT, flags);
}
if (surface) { if (RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface()) {
customCursor = nsContentUtils::SurfaceToIPCImage(*dataSurface);
}
}
}
bool PuppetWidget::NeedsPaint() { // e10s popups are handled by the parent process, so never should be painted // here return mVisible;
}
LayoutDeviceIntPoint PuppetWidget::GetChromeOffset() { if (!GetOwningBrowserChild()) {
NS_WARNING("PuppetWidget without Tab does not have chrome information."); return LayoutDeviceIntPoint();
} return GetOwningBrowserChild()->GetChromeOffset();
}
// If there is different text event dispatcher listener for handling // text event dispatcher, that means that native keyboard events and // IME events are handled in this process. Therefore, we don't need // to send any requests and notifications to the parent process. if (mNativeTextEventDispatcherListener) { return NS_ERROR_NOT_IMPLEMENTED;
}
switch (aIMENotification.mMessage) { case REQUEST_TO_COMMIT_COMPOSITION: return RequestIMEToCommitComposition(false); case REQUEST_TO_CANCEL_COMPOSITION: return RequestIMEToCommitComposition(true); case NOTIFY_IME_OF_FOCUS: case NOTIFY_IME_OF_BLUR: return NotifyIMEOfFocusChange(aIMENotification); case NOTIFY_IME_OF_SELECTION_CHANGE: return NotifyIMEOfSelectionChange(aIMENotification); case NOTIFY_IME_OF_TEXT_CHANGE: return NotifyIMEOfTextChange(aIMENotification); case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED: return NotifyIMEOfCompositionUpdate(aIMENotification); case NOTIFY_IME_OF_MOUSE_BUTTON_EVENT: return NotifyIMEOfMouseButtonEvent(aIMENotification); case NOTIFY_IME_OF_POSITION_CHANGE: return NotifyIMEOfPositionChange(aIMENotification); default: return NS_ERROR_NOT_IMPLEMENTED;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.