nsDOMWindowUtils.cpp (155671B)
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 7 #include "nsDOMWindowUtils.h" 8 9 #include <algorithm> 10 11 #include "CubebDeviceEnumerator.h" 12 #include "LayoutConstants.h" 13 #include "MobileViewportManager.h" 14 #include "js/Object.h" // JS::GetClass 15 #include "js/experimental/PCCountProfiling.h" // JS::{Start,Stop}PCCountProfiling, JS::PurgePCCounts, JS::GetPCCountScript{Count,Summary,Contents} 16 #include "mozilla/Base64.h" 17 #include "mozilla/ChaosMode.h" 18 #include "mozilla/EventStateManager.h" 19 #include "mozilla/InputTaskManager.h" 20 #include "mozilla/Logging.h" 21 #include "mozilla/MiscEvents.h" 22 #include "mozilla/MouseEvents.h" 23 #include "mozilla/PresShell.h" 24 #include "mozilla/PresShellInlines.h" 25 #include "mozilla/ScrollContainerFrame.h" 26 #include "mozilla/ServoStyleSet.h" 27 #include "mozilla/StaticPrefs_layout.h" 28 #include "mozilla/StaticPrefs_test.h" 29 #include "mozilla/StyleAnimationValue.h" 30 #include "mozilla/TextEventDispatcher.h" 31 #include "mozilla/TextEvents.h" 32 #include "mozilla/TouchEvents.h" 33 #include "mozilla/css/Loader.h" 34 #include "mozilla/dom/Animation.h" 35 #include "mozilla/dom/BindingDeclarations.h" 36 #include "mozilla/dom/BlobBinding.h" 37 #include "mozilla/dom/DOMCollectedFramesBinding.h" 38 #include "mozilla/dom/DOMRect.h" 39 #include "mozilla/dom/DocumentInlines.h" 40 #include "mozilla/dom/DocumentTimeline.h" 41 #include "mozilla/dom/Event.h" 42 #include "mozilla/dom/File.h" 43 #include "mozilla/dom/FileBinding.h" 44 #include "mozilla/dom/FunctionBinding.h" 45 #include "mozilla/dom/MouseEventBinding.h" 46 #include "mozilla/dom/Touch.h" 47 #include "mozilla/dom/UserActivation.h" 48 #include "mozilla/layers/APZCCallbackHelper.h" 49 #include "mozilla/layers/CompositorBridgeChild.h" 50 #include "mozilla/layers/PCompositorBridgeTypes.h" 51 #include "mozilla/layers/TouchActionHelper.h" 52 #include "mozilla/media/MediaUtils.h" 53 #include "nsCSSProps.h" 54 #include "nsCaret.h" 55 #include "nsCharsetSource.h" 56 #include "nsComputedDOMStyle.h" 57 #include "nsContentList.h" 58 #include "nsContentUtils.h" 59 #include "nsDeviceContext.h" 60 #include "nsError.h" 61 #include "nsFocusManager.h" 62 #include "nsFrameManager.h" 63 #include "nsGlobalWindowOuter.h" 64 #include "nsIDocShell.h" 65 #include "nsIFrame.h" 66 #include "nsIObjectLoadingContent.h" 67 #include "nsIWidget.h" 68 #include "nsJSEnvironment.h" 69 #include "nsJSUtils.h" 70 #include "nsLayoutUtils.h" 71 #include "nsMenuPopupFrame.h" 72 #include "nsPresContext.h" 73 #include "nsQueryContentEventResult.h" 74 #include "nsQueryObject.h" 75 #include "nsRefreshDriver.h" 76 #include "nsStyleUtil.h" 77 78 #if defined(MOZ_WIDGET_GTK) 79 # include <gdk/gdk.h> 80 # if defined(MOZ_X11) 81 # include <gdk/gdkx.h> 82 83 # include "X11UndefineNone.h" 84 # endif 85 #endif 86 87 #include "mozilla/dom/AudioDeviceInfo.h" 88 #include "mozilla/dom/BrowserChild.h" 89 #include "mozilla/dom/ContentChild.h" 90 #include "mozilla/dom/Element.h" 91 #include "mozilla/dom/IDBFactoryBinding.h" 92 #include "mozilla/dom/IndexedDatabaseManager.h" 93 #include "mozilla/dom/PermissionMessageUtils.h" 94 #include "mozilla/dom/Text.h" 95 #include "mozilla/dom/quota/PersistenceType.h" 96 #include "mozilla/dom/quota/PrincipalUtils.h" 97 #include "mozilla/layers/FrameUniformityData.h" 98 #include "nsIFormControl.h" 99 #include "nsPrintfCString.h" 100 #include "nsViewportInfo.h" 101 // #include "nsWidgetsCID.h" 102 #include "HTMLCanvasElement.h" 103 #include "HTMLImageElement.h" 104 #include "mozilla/CSSPropertyId.h" 105 #include "mozilla/CycleCollectedJSContext.h" 106 #include "mozilla/DisplayPortUtils.h" 107 #include "mozilla/IMEContentObserver.h" 108 #include "mozilla/IMEStateManager.h" 109 #include "mozilla/Preferences.h" 110 #include "mozilla/PreloadedStyleSheet.h" 111 #include "mozilla/ProfilerLabels.h" 112 #include "mozilla/ProfilerMarkers.h" 113 #include "mozilla/RDDProcessManager.h" 114 #include "mozilla/ServoBindings.h" 115 #include "mozilla/StyleSheetInlines.h" 116 #include "mozilla/ViewportUtils.h" 117 #include "mozilla/WheelHandlingHelper.h" 118 #include "mozilla/css/ImageLoader.h" 119 #include "mozilla/dom/BrowsingContextGroup.h" 120 #include "mozilla/dom/Document.h" 121 #include "mozilla/dom/Promise.h" 122 #include "mozilla/dom/TimeoutManager.h" 123 #include "mozilla/gfx/GPUProcessManager.h" 124 #include "mozilla/gfx/gfxVars.h" 125 #include "mozilla/layers/IAPZCTreeManager.h" // for layers::ZoomToRectBehavior 126 #include "mozilla/layers/WebRenderBridgeChild.h" 127 #include "mozilla/layers/WebRenderLayerManager.h" 128 #include "nsCSSPseudoElements.h" // for PseudoStyleType 129 #include "nsContentPermissionHelper.h" 130 #include "nsDisplayList.h" 131 #include "nsIBaseWindow.h" 132 #include "nsIDocShellTreeOwner.h" 133 #include "nsIInterfaceRequestorUtils.h" 134 #include "nsNetUtil.h" 135 #include "nsROCSSPrimitiveValue.h" 136 137 #ifdef XP_WIN 138 # include <direct.h> 139 #else 140 # include <sys/stat.h> 141 #endif 142 143 #ifdef XP_WIN 144 # undef GetClassName 145 #endif 146 147 using namespace mozilla; 148 using namespace mozilla::dom; 149 using namespace mozilla::ipc; 150 using namespace mozilla::layers; 151 using namespace mozilla::widget; 152 using namespace mozilla::gfx; 153 154 static LazyLogModule sApzZoomToFocusedInputLog("apz.zoomtofocusedinput"); 155 #define APZZTFI_LOG(...) \ 156 MOZ_LOG(sApzZoomToFocusedInputLog, LogLevel::Debug, (__VA_ARGS__)) 157 158 class gfxContext; 159 160 class OldWindowSize : public LinkedListElement<OldWindowSize> { 161 public: 162 static void Set(nsIWeakReference* aWindowRef, const nsSize& aSize) { 163 OldWindowSize* item = GetItem(aWindowRef); 164 if (item) { 165 item->mSize = aSize; 166 } else { 167 item = new OldWindowSize(aWindowRef, aSize); 168 sList.insertBack(item); 169 } 170 } 171 172 static nsSize GetAndRemove(nsIWeakReference* aWindowRef) { 173 nsSize result; 174 if (OldWindowSize* item = GetItem(aWindowRef)) { 175 result = item->mSize; 176 delete item; 177 } 178 return result; 179 } 180 181 private: 182 explicit OldWindowSize(nsIWeakReference* aWindowRef, const nsSize& aSize) 183 : mWindowRef(aWindowRef), mSize(aSize) {} 184 ~OldWindowSize() = default; 185 ; 186 187 static OldWindowSize* GetItem(nsIWeakReference* aWindowRef) { 188 OldWindowSize* item = sList.getFirst(); 189 while (item && item->mWindowRef != aWindowRef) { 190 item = item->getNext(); 191 } 192 return item; 193 } 194 195 static LinkedList<OldWindowSize> sList; 196 nsWeakPtr mWindowRef; 197 nsSize mSize; 198 }; 199 200 namespace { 201 202 class NativeInputRunnable final : public PrioritizableRunnable { 203 explicit NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent); 204 ~NativeInputRunnable() = default; 205 206 public: 207 static already_AddRefed<nsIRunnable> Create( 208 already_AddRefed<nsIRunnable>&& aEvent); 209 }; 210 211 NativeInputRunnable::NativeInputRunnable(already_AddRefed<nsIRunnable>&& aEvent) 212 : PrioritizableRunnable(std::move(aEvent), 213 nsIRunnablePriority::PRIORITY_INPUT_HIGH) {} 214 215 /* static */ 216 already_AddRefed<nsIRunnable> NativeInputRunnable::Create( 217 already_AddRefed<nsIRunnable>&& aEvent) { 218 MOZ_ASSERT(NS_IsMainThread()); 219 nsCOMPtr<nsIRunnable> event(new NativeInputRunnable(std::move(aEvent))); 220 return event.forget(); 221 } 222 223 } // unnamed namespace 224 225 MOZ_RUNINIT LinkedList<OldWindowSize> OldWindowSize::sList; 226 227 NS_INTERFACE_MAP_BEGIN(nsDOMWindowUtils) 228 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMWindowUtils) 229 NS_INTERFACE_MAP_ENTRY(nsIDOMWindowUtils) 230 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 231 NS_INTERFACE_MAP_END 232 233 NS_IMPL_ADDREF(nsDOMWindowUtils) 234 NS_IMPL_RELEASE(nsDOMWindowUtils) 235 236 nsDOMWindowUtils::nsDOMWindowUtils(nsGlobalWindowOuter* aWindow) { 237 nsCOMPtr<nsISupports> supports = do_QueryObject(aWindow); 238 mWindow = do_GetWeakReference(supports); 239 } 240 241 nsDOMWindowUtils::~nsDOMWindowUtils() { OldWindowSize::GetAndRemove(mWindow); } 242 243 nsIDocShell* nsDOMWindowUtils::GetDocShell() { 244 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 245 if (!window) { 246 return nullptr; 247 } 248 return window->GetDocShell(); 249 } 250 251 PresShell* nsDOMWindowUtils::GetPresShell() { 252 nsIDocShell* docShell = GetDocShell(); 253 if (!docShell) { 254 return nullptr; 255 } 256 return docShell->GetPresShell(); 257 } 258 259 nsPresContext* nsDOMWindowUtils::GetPresContext() { 260 nsIDocShell* docShell = GetDocShell(); 261 if (!docShell) { 262 return nullptr; 263 } 264 return docShell->GetPresContext(); 265 } 266 267 Document* nsDOMWindowUtils::GetDocument() { 268 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 269 if (!window) { 270 return nullptr; 271 } 272 return window->GetExtantDoc(); 273 } 274 275 WebRenderBridgeChild* nsDOMWindowUtils::GetWebRenderBridge() { 276 if (nsIWidget* widget = GetWidget()) { 277 if (WindowRenderer* renderer = widget->GetWindowRenderer()) { 278 if (WebRenderLayerManager* wr = renderer->AsWebRender()) { 279 return wr->WrBridge(); 280 } 281 } 282 } 283 return nullptr; 284 } 285 286 CompositorBridgeChild* nsDOMWindowUtils::GetCompositorBridge() { 287 if (nsIWidget* widget = GetWidget()) { 288 if (WindowRenderer* renderer = widget->GetWindowRenderer()) { 289 if (CompositorBridgeChild* cbc = renderer->GetCompositorBridgeChild()) { 290 return cbc; 291 } 292 } 293 } 294 return nullptr; 295 } 296 297 nsresult nsDOMWindowUtils::GetWidgetOpaqueRegion( 298 nsTArray<RefPtr<DOMRect>>& aRects) { 299 const nsPresContext* pc = GetPresContext(); 300 nsIWidget* widget = GetWidget(); 301 if (!widget || !pc) { 302 return NS_ERROR_FAILURE; 303 } 304 auto AddRect = [&](const LayoutDeviceIntRect& aRect) { 305 RefPtr rect = new DOMRect(mWindow); 306 CSSRect cssRect = aRect / pc->CSSToDevPixelScale(); 307 rect->SetRect(cssRect.x, cssRect.y, cssRect.width, cssRect.height); 308 aRects.AppendElement(std::move(rect)); 309 }; 310 if (widget->GetTransparencyMode() == TransparencyMode::Opaque) { 311 AddRect( 312 LayoutDeviceIntRect(LayoutDeviceIntPoint(), widget->GetClientSize())); 313 return NS_OK; 314 } 315 auto region = widget->GetOpaqueRegionForTesting(); 316 for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) { 317 AddRect(iter.Get()); 318 } 319 return NS_OK; 320 } 321 322 NS_IMETHODIMP 323 nsDOMWindowUtils::GetLastOverWindowPointerLocationInCSSPixels(float* aX, 324 float* aY) { 325 const PresShell* presShell = GetPresShell(); 326 const nsPresContext* presContext = GetPresContext(); 327 328 if (!presShell || !presContext) { 329 return NS_ERROR_FAILURE; 330 } 331 332 const nsPoint& lastOverWindowPointerLocation = 333 presShell->GetLastOverWindowPointerLocation(); 334 335 if (lastOverWindowPointerLocation.X() == NS_UNCONSTRAINEDSIZE && 336 lastOverWindowPointerLocation.Y() == NS_UNCONSTRAINEDSIZE) { 337 *aX = 0; 338 *aY = 0; 339 } else { 340 const CSSPoint lastOverWindowPointerLocationInCSSPixels = 341 CSSPoint::FromAppUnits(lastOverWindowPointerLocation); 342 *aX = lastOverWindowPointerLocationInCSSPixels.X(); 343 *aY = lastOverWindowPointerLocationInCSSPixels.Y(); 344 } 345 346 return NS_OK; 347 } 348 349 NS_IMETHODIMP 350 nsDOMWindowUtils::SyncFlushCompositor() { 351 if (nsIWidget* widget = GetWidget()) { 352 if (WindowRenderer* renderer = widget->GetWindowRenderer()) { 353 if (KnowsCompositor* kc = renderer->AsKnowsCompositor()) { 354 kc->SyncWithCompositor(); 355 } 356 } 357 } 358 return NS_OK; 359 } 360 361 NS_IMETHODIMP 362 nsDOMWindowUtils::GetImageAnimationMode(uint16_t* aMode) { 363 NS_ENSURE_ARG_POINTER(aMode); 364 *aMode = 0; 365 nsPresContext* presContext = GetPresContext(); 366 if (presContext) { 367 *aMode = presContext->ImageAnimationMode(); 368 return NS_OK; 369 } 370 return NS_ERROR_NOT_AVAILABLE; 371 } 372 373 NS_IMETHODIMP 374 nsDOMWindowUtils::SetImageAnimationMode(uint16_t aMode) { 375 nsPresContext* presContext = GetPresContext(); 376 if (presContext) { 377 presContext->SetImageAnimationMode(aMode); 378 return NS_OK; 379 } 380 return NS_ERROR_NOT_AVAILABLE; 381 } 382 383 NS_IMETHODIMP 384 nsDOMWindowUtils::GetDocCharsetIsForced(bool* aIsForced) { 385 *aIsForced = false; 386 387 Document* doc = GetDocument(); 388 if (doc) { 389 auto source = doc->GetDocumentCharacterSetSource(); 390 *aIsForced = source == kCharsetFromInitialUserForcedAutoDetection || 391 source == kCharsetFromFinalUserForcedAutoDetection; 392 } 393 return NS_OK; 394 } 395 396 NS_IMETHODIMP 397 nsDOMWindowUtils::GetPhysicalMillimeterInCSSPixels(float* aPhysicalMillimeter) { 398 nsPresContext* presContext = GetPresContext(); 399 if (!presContext) { 400 return NS_ERROR_NOT_AVAILABLE; 401 } 402 403 *aPhysicalMillimeter = nsPresContext::AppUnitsToFloatCSSPixels( 404 presContext->PhysicalMillimetersToAppUnits(1)); 405 return NS_OK; 406 } 407 408 NS_IMETHODIMP 409 nsDOMWindowUtils::GetDocumentMetadata(const nsAString& aName, 410 nsAString& aValue) { 411 Document* doc = GetDocument(); 412 if (doc) { 413 RefPtr<nsAtom> name = NS_Atomize(aName); 414 doc->GetHeaderData(name, aValue); 415 return NS_OK; 416 } 417 418 aValue.Truncate(); 419 return NS_OK; 420 } 421 422 NS_IMETHODIMP 423 nsDOMWindowUtils::UpdateLayerTree() { 424 FlushLayoutWithoutThrottledAnimations(); 425 if (RefPtr<PresShell> ps = GetPresShell()) { 426 nsAutoScriptBlocker scriptBlocker; 427 RefPtr renderer = ps->GetWindowRenderer(); 428 ps->PaintAndRequestComposite(ps->GetRootFrame(), renderer, 429 PaintFlags::PaintSyncDecodeImages); 430 renderer->WaitOnTransactionProcessed(); 431 } 432 return NS_OK; 433 } 434 435 NS_IMETHODIMP 436 nsDOMWindowUtils::GetDocumentViewerSize(uint32_t* aDisplayWidth, 437 uint32_t* aDisplayHeight) { 438 PresShell* presShell = GetPresShell(); 439 LayoutDeviceIntSize displaySize; 440 441 if (!presShell || !nsLayoutUtils::GetDocumentViewerSize( 442 presShell->GetPresContext(), displaySize)) { 443 return NS_ERROR_FAILURE; 444 } 445 446 *aDisplayWidth = displaySize.width; 447 *aDisplayHeight = displaySize.height; 448 449 return NS_OK; 450 } 451 452 NS_IMETHODIMP 453 nsDOMWindowUtils::GetViewportInfo(uint32_t aDisplayWidth, 454 uint32_t aDisplayHeight, double* aDefaultZoom, 455 bool* aAllowZoom, double* aMinZoom, 456 double* aMaxZoom, uint32_t* aWidth, 457 uint32_t* aHeight, bool* aAutoSize) { 458 Document* doc = GetDocument(); 459 NS_ENSURE_STATE(doc); 460 461 nsViewportInfo info = 462 doc->GetViewportInfo(ScreenIntSize(aDisplayWidth, aDisplayHeight)); 463 *aDefaultZoom = info.GetDefaultZoom().scale; 464 *aAllowZoom = info.IsZoomAllowed(); 465 *aMinZoom = info.GetMinZoom().scale; 466 *aMaxZoom = info.GetMaxZoom().scale; 467 CSSIntSize size = gfx::RoundedToInt(info.GetSize()); 468 *aWidth = size.width; 469 *aHeight = size.height; 470 *aAutoSize = info.IsAutoSizeEnabled(); 471 return NS_OK; 472 } 473 474 NS_IMETHODIMP 475 nsDOMWindowUtils::GetViewportFitInfo(nsAString& aViewportFit) { 476 Document* doc = GetDocument(); 477 NS_ENSURE_STATE(doc); 478 479 ViewportMetaData metaData = doc->GetViewportMetaData(); 480 if (metaData.mViewportFit.EqualsLiteral("contain")) { 481 aViewportFit.AssignLiteral("contain"); 482 } else if (metaData.mViewportFit.EqualsLiteral("cover")) { 483 aViewportFit.AssignLiteral("cover"); 484 } else { 485 aViewportFit.AssignLiteral("auto"); 486 } 487 return NS_OK; 488 } 489 490 NS_IMETHODIMP 491 nsDOMWindowUtils::SetMousewheelAutodir(Element* aElement, bool aEnabled, 492 bool aHonourRoot) { 493 aElement->SetProperty(nsGkAtoms::forceMousewheelAutodir, 494 reinterpret_cast<void*>(aEnabled)); 495 aElement->SetProperty(nsGkAtoms::forceMousewheelAutodirHonourRoot, 496 reinterpret_cast<void*>(aHonourRoot)); 497 return NS_OK; 498 } 499 500 NS_IMETHODIMP 501 nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx, 502 float aWidthPx, float aHeightPx, 503 Element* aElement, 504 uint32_t aPriority) { 505 PresShell* presShell = GetPresShell(); 506 if (!presShell) { 507 return NS_ERROR_FAILURE; 508 } 509 510 if (!aElement) { 511 return NS_ERROR_INVALID_ARG; 512 } 513 514 if (aElement->GetUncomposedDoc() != presShell->GetDocument()) { 515 return NS_ERROR_INVALID_ARG; 516 } 517 518 bool hadDisplayPort = false; 519 bool wasPainted = false; 520 nsRect oldDisplayPort; 521 { 522 DisplayPortPropertyData* currentData = 523 static_cast<DisplayPortPropertyData*>( 524 aElement->GetProperty(nsGkAtoms::DisplayPort)); 525 if (currentData) { 526 if (currentData->mPriority > aPriority) { 527 return NS_OK; 528 } 529 hadDisplayPort = true; 530 oldDisplayPort = currentData->mRect; 531 wasPainted = currentData->mPainted; 532 } 533 } 534 535 nsRect displayport(nsPresContext::CSSPixelsToAppUnits(aXPx), 536 nsPresContext::CSSPixelsToAppUnits(aYPx), 537 nsPresContext::CSSPixelsToAppUnits(aWidthPx), 538 nsPresContext::CSSPixelsToAppUnits(aHeightPx)); 539 540 aElement->RemoveProperty(nsGkAtoms::MinimalDisplayPort); 541 aElement->SetProperty( 542 nsGkAtoms::DisplayPort, 543 new DisplayPortPropertyData(displayport, aPriority, wasPainted), 544 nsINode::DeleteProperty<DisplayPortPropertyData>); 545 546 DisplayPortUtils::InvalidateForDisplayPortChange(aElement, hadDisplayPort, 547 oldDisplayPort, displayport); 548 549 nsIFrame* rootFrame = presShell->GetRootFrame(); 550 if (rootFrame) { 551 rootFrame->SchedulePaint(); 552 553 // If we are hiding something that is a display root then send empty paint 554 // transaction in order to release retained layers because it won't get 555 // any more paint requests when it is hidden. 556 if (displayport.IsEmpty() && 557 rootFrame == nsLayoutUtils::GetDisplayRootFrame(rootFrame)) { 558 nsCOMPtr<nsIWidget> widget = GetWidget(); 559 if (widget) { 560 using PaintFrameFlags = nsLayoutUtils::PaintFrameFlags; 561 nsLayoutUtils::PaintFrame( 562 nullptr, rootFrame, nsRegion(), NS_RGB(255, 255, 255), 563 nsDisplayListBuilderMode::Painting, PaintFrameFlags::WidgetLayers); 564 } 565 } 566 } 567 568 return NS_OK; 569 } 570 571 NS_IMETHODIMP 572 nsDOMWindowUtils::SetDisplayPortMarginsForElement( 573 float aLeftMargin, float aTopMargin, float aRightMargin, 574 float aBottomMargin, Element* aElement, uint32_t aPriority) { 575 PresShell* presShell = GetPresShell(); 576 if (!presShell) { 577 return NS_ERROR_FAILURE; 578 } 579 580 if (!aElement) { 581 return NS_ERROR_INVALID_ARG; 582 } 583 584 if (aElement->GetUncomposedDoc() != presShell->GetDocument()) { 585 return NS_ERROR_INVALID_ARG; 586 } 587 588 // Note order change of arguments between our function signature and 589 // ScreenMargin constructor. 590 ScreenMargin displayportMargins(aTopMargin, aRightMargin, aBottomMargin, 591 aLeftMargin); 592 593 DisplayPortUtils::SetDisplayPortMargins( 594 aElement, presShell, 595 DisplayPortMargins::ForContent(aElement, displayportMargins), 596 DisplayPortUtils::ClearMinimalDisplayPortProperty::Yes, aPriority); 597 598 return NS_OK; 599 } 600 601 NS_IMETHODIMP 602 nsDOMWindowUtils::SetDisplayPortBaseForElement(int32_t aX, int32_t aY, 603 int32_t aWidth, int32_t aHeight, 604 Element* aElement) { 605 PresShell* presShell = GetPresShell(); 606 if (!presShell) { 607 return NS_ERROR_FAILURE; 608 } 609 610 if (!aElement) { 611 return NS_ERROR_INVALID_ARG; 612 } 613 614 if (aElement->GetUncomposedDoc() != presShell->GetDocument()) { 615 return NS_ERROR_INVALID_ARG; 616 } 617 618 DisplayPortUtils::SetDisplayPortBase(aElement, 619 nsRect(aX, aY, aWidth, aHeight)); 620 621 return NS_OK; 622 } 623 624 NS_IMETHODIMP 625 nsDOMWindowUtils::GetScrollbarSizes(Element* aElement, 626 uint32_t* aOutVerticalScrollbarWidth, 627 uint32_t* aOutHorizontalScrollbarHeight) { 628 ScrollContainerFrame* scrollContainerFrame = 629 nsLayoutUtils::FindScrollContainerFrameFor(aElement); 630 if (!scrollContainerFrame) { 631 return NS_ERROR_INVALID_ARG; 632 } 633 634 CSSIntMargin scrollbarSizes = RoundedToInt( 635 CSSMargin::FromAppUnits(scrollContainerFrame->GetActualScrollbarSizes( 636 ScrollContainerFrame::ScrollbarSizesOptions:: 637 INCLUDE_VISUAL_VIEWPORT_SCROLLBARS))); 638 *aOutVerticalScrollbarWidth = scrollbarSizes.LeftRight(); 639 *aOutHorizontalScrollbarHeight = scrollbarSizes.TopBottom(); 640 641 return NS_OK; 642 } 643 644 NS_IMETHODIMP 645 nsDOMWindowUtils::SetResolutionAndScaleTo(float aResolution) { 646 PresShell* presShell = GetPresShell(); 647 if (!presShell) { 648 return NS_ERROR_FAILURE; 649 } 650 651 presShell->SetResolutionAndScaleTo(aResolution, ResolutionChangeOrigin::Test); 652 653 return NS_OK; 654 } 655 656 NS_IMETHODIMP 657 nsDOMWindowUtils::SetRestoreResolution(float aResolution, 658 uint32_t aDisplayWidth, 659 uint32_t aDisplayHeight) { 660 PresShell* presShell = GetPresShell(); 661 if (!presShell) { 662 return NS_ERROR_FAILURE; 663 } 664 665 presShell->SetRestoreResolution( 666 aResolution, LayoutDeviceIntSize(aDisplayWidth, aDisplayHeight)); 667 668 return NS_OK; 669 } 670 671 NS_IMETHODIMP 672 nsDOMWindowUtils::GetResolution(float* aResolution) { 673 PresShell* presShell = GetPresShell(); 674 if (!presShell) { 675 return NS_ERROR_FAILURE; 676 } 677 678 *aResolution = presShell->GetResolution(); 679 680 return NS_OK; 681 } 682 683 NS_IMETHODIMP 684 nsDOMWindowUtils::SetIsFirstPaint(bool aIsFirstPaint) { 685 if (PresShell* presShell = GetPresShell()) { 686 presShell->SetIsFirstPaint(aIsFirstPaint); 687 return NS_OK; 688 } 689 return NS_ERROR_FAILURE; 690 } 691 692 NS_IMETHODIMP 693 nsDOMWindowUtils::GetIsFirstPaint(bool* aIsFirstPaint) { 694 if (PresShell* presShell = GetPresShell()) { 695 *aIsFirstPaint = presShell->GetIsFirstPaint(); 696 return NS_OK; 697 } 698 return NS_ERROR_FAILURE; 699 } 700 701 NS_IMETHODIMP 702 nsDOMWindowUtils::GetPresShellId(uint32_t* aPresShellId) { 703 if (PresShell* presShell = GetPresShell()) { 704 *aPresShellId = presShell->GetPresShellId(); 705 return NS_OK; 706 } 707 return NS_ERROR_FAILURE; 708 } 709 710 NS_IMETHODIMP 711 nsDOMWindowUtils::IsCORSSafelistedRequestHeader(const nsACString& aName, 712 const nsACString& aValue, 713 bool* aRetVal) { 714 NS_ENSURE_ARG_POINTER(aRetVal); 715 *aRetVal = nsContentUtils::IsCORSSafelistedRequestHeader(aName, aValue); 716 return NS_OK; 717 } 718 719 NS_IMETHODIMP 720 nsDOMWindowUtils::SendWheelEvent(float aX, float aY, double aDeltaX, 721 double aDeltaY, double aDeltaZ, 722 uint32_t aDeltaMode, int32_t aModifiers, 723 int32_t aLineOrPageDeltaX, 724 int32_t aLineOrPageDeltaY, uint32_t aOptions, 725 nsISynthesizedEventCallback* aCallback) { 726 if (XRE_IsContentProcess() && aCallback && 727 ((aOptions & WHEEL_EVENT_ASYNC_ENABLED) || 728 StaticPrefs::test_events_async_enabled())) { 729 NS_WARNING( 730 "nsDOMWindowUtils::SendWheelEvent() does not support being called in " 731 "the content process with both a callback and async enabled"); 732 return NS_ERROR_FAILURE; 733 } 734 735 // get the widget to send the event to 736 nsPoint offset; 737 nsCOMPtr<nsIWidget> widget = GetWidget(&offset); 738 if (!widget) { 739 return NS_ERROR_NULL_POINTER; 740 } 741 742 mozilla::widget::AutoSynthesizedEventCallbackNotifier notifier(aCallback); 743 744 WidgetWheelEvent wheelEvent(true, eWheel, widget); 745 wheelEvent.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers); 746 wheelEvent.mDeltaX = aDeltaX; 747 wheelEvent.mDeltaY = aDeltaY; 748 wheelEvent.mDeltaZ = aDeltaZ; 749 wheelEvent.mDeltaMode = aDeltaMode; 750 wheelEvent.mIsMomentum = (aOptions & WHEEL_EVENT_CAUSED_BY_MOMENTUM) != 0; 751 wheelEvent.mIsNoLineOrPageDelta = 752 (aOptions & WHEEL_EVENT_CAUSED_BY_NO_LINE_OR_PAGE_DELTA_DEVICE) != 0; 753 wheelEvent.mCustomizedByUserPrefs = 754 (aOptions & WHEEL_EVENT_CUSTOMIZED_BY_USER_PREFS) != 0; 755 wheelEvent.mLineOrPageDeltaX = aLineOrPageDeltaX; 756 wheelEvent.mLineOrPageDeltaY = aLineOrPageDeltaY; 757 wheelEvent.mCallbackId = notifier.SaveCallback(); 758 759 nsPresContext* presContext = GetPresContext(); 760 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); 761 762 wheelEvent.mRefPoint = 763 nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext); 764 765 if ((aOptions & WHEEL_EVENT_ASYNC_ENABLED) || 766 StaticPrefs::test_events_async_enabled()) { 767 widget->DispatchInputEvent(&wheelEvent); 768 } else { 769 widget->DispatchEvent(&wheelEvent); 770 } 771 772 // The callback ID may be cleared when the event also needs to be dispatched 773 // to a content process. In such cases, the callback will be notified after 774 // the event has been dispatched in the target content process. 775 if (wheelEvent.mCallbackId.isSome()) { 776 mozilla::widget::AutoSynthesizedEventCallbackNotifier::NotifySavedCallback( 777 wheelEvent.mCallbackId.ref()); 778 } 779 780 if (widget->AsyncPanZoomEnabled()) { 781 // Computing overflow deltas is not compatible with APZ, so if APZ is 782 // enabled, we skip testing it. 783 return NS_OK; 784 } 785 786 bool failedX = false; 787 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_ZERO) && 788 wheelEvent.mOverflowDeltaX != 0) { 789 failedX = true; 790 } 791 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_POSITIVE) && 792 wheelEvent.mOverflowDeltaX <= 0) { 793 failedX = true; 794 } 795 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_X_NEGATIVE) && 796 wheelEvent.mOverflowDeltaX >= 0) { 797 failedX = true; 798 } 799 bool failedY = false; 800 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_ZERO) && 801 wheelEvent.mOverflowDeltaY != 0) { 802 failedY = true; 803 } 804 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_POSITIVE) && 805 wheelEvent.mOverflowDeltaY <= 0) { 806 failedY = true; 807 } 808 if ((aOptions & WHEEL_EVENT_EXPECTED_OVERFLOW_DELTA_Y_NEGATIVE) && 809 wheelEvent.mOverflowDeltaY >= 0) { 810 failedY = true; 811 } 812 813 #ifdef DEBUG 814 if (failedX) { 815 nsPrintfCString debugMsg("SendWheelEvent(): unexpected mOverflowDeltaX: %f", 816 wheelEvent.mOverflowDeltaX); 817 NS_WARNING(debugMsg.get()); 818 } 819 if (failedY) { 820 nsPrintfCString debugMsg("SendWheelEvent(): unexpected mOverflowDeltaY: %f", 821 wheelEvent.mOverflowDeltaY); 822 NS_WARNING(debugMsg.get()); 823 } 824 #endif 825 826 return (!failedX && !failedY) ? NS_OK : NS_ERROR_FAILURE; 827 } 828 829 NS_IMETHODIMP 830 nsDOMWindowUtils::SendTouchEvent( 831 const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers, 832 const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs, 833 const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys, 834 const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces, 835 const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs, 836 const nsTArray<int32_t>& aTwists, int32_t aModifiers, 837 AsyncEnabledOption aAsyncEnabled, bool* aPreventDefault) { 838 return SendTouchEventCommon( 839 aType, aIdentifiers, aXs, aYs, aRxs, aRys, aRotationAngles, aForces, 840 aTiltXs, aTiltYs, aTwists, aModifiers, /* aIsPen */ false, 841 /* aToWindow */ false, aAsyncEnabled, aPreventDefault); 842 } 843 844 NS_IMETHODIMP 845 nsDOMWindowUtils::SendTouchEventAsPen( 846 const nsAString& aType, uint32_t aIdentifier, int32_t aX, int32_t aY, 847 uint32_t aRx, uint32_t aRy, float aRotationAngle, float aForce, 848 int32_t aTiltX, int32_t aTiltY, int32_t aTwist, int32_t aModifier, 849 AsyncEnabledOption aAsyncEnabled, bool* aPreventDefault) { 850 return SendTouchEventCommon( 851 aType, nsTArray{aIdentifier}, nsTArray{aX}, nsTArray{aY}, nsTArray{aRx}, 852 nsTArray{aRy}, nsTArray{aRotationAngle}, nsTArray{aForce}, 853 nsTArray{aTiltX}, nsTArray{aTiltY}, nsTArray{aTwist}, aModifier, 854 /* aIsPen */ true, /* aToWindow */ false, aAsyncEnabled, aPreventDefault); 855 } 856 857 NS_IMETHODIMP 858 nsDOMWindowUtils::SendTouchEventToWindow( 859 const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers, 860 const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs, 861 const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys, 862 const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces, 863 const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs, 864 const nsTArray<int32_t>& aTwists, int32_t aModifiers, 865 bool* aPreventDefault) { 866 return SendTouchEventCommon( 867 aType, aIdentifiers, aXs, aYs, aRxs, aRys, aRotationAngles, aForces, 868 aTiltXs, aTiltYs, aTwists, aModifiers, /* aIsPen */ false, 869 /* aToWindow */ true, AsyncEnabledOption::ASYNC_DISABLED, 870 aPreventDefault); 871 } 872 873 nsresult nsDOMWindowUtils::SendTouchEventCommon( 874 const nsAString& aType, const nsTArray<uint32_t>& aIdentifiers, 875 const nsTArray<int32_t>& aXs, const nsTArray<int32_t>& aYs, 876 const nsTArray<uint32_t>& aRxs, const nsTArray<uint32_t>& aRys, 877 const nsTArray<float>& aRotationAngles, const nsTArray<float>& aForces, 878 const nsTArray<int32_t>& aTiltXs, const nsTArray<int32_t>& aTiltYs, 879 const nsTArray<int32_t>& aTwists, int32_t aModifiers, bool aIsPen, 880 bool aToWindow, AsyncEnabledOption aAsyncEnabled, bool* aPreventDefault) { 881 // get the widget to send the event to 882 nsPoint offset; 883 nsCOMPtr<nsIWidget> widget = GetWidget(&offset); 884 if (!widget) { 885 return NS_ERROR_NULL_POINTER; 886 } 887 EventMessage msg; 888 if (aType.EqualsLiteral("touchstart")) { 889 msg = eTouchStart; 890 } else if (aType.EqualsLiteral("touchmove")) { 891 msg = eTouchMove; 892 } else if (aType.EqualsLiteral("touchend")) { 893 msg = eTouchEnd; 894 } else if (aType.EqualsLiteral("touchcancel")) { 895 msg = eTouchCancel; 896 } else { 897 return NS_ERROR_UNEXPECTED; 898 } 899 WidgetTouchEvent event(true, msg, widget); 900 event.mFlags.mIsSynthesizedForTests = true; 901 event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers); 902 if (aIsPen) { 903 event.mInputSource = MouseEvent_Binding::MOZ_SOURCE_PEN; 904 } 905 906 nsPresContext* presContext = GetPresContext(); 907 if (!presContext) { 908 return NS_ERROR_FAILURE; 909 } 910 uint32_t count = aIdentifiers.Length(); 911 if (aXs.Length() != count || aYs.Length() != count || 912 aRxs.Length() != count || aRys.Length() != count || 913 aRotationAngles.Length() != count || aForces.Length() != count) { 914 return NS_ERROR_INVALID_ARG; 915 } 916 event.mTouches.SetCapacity(count); 917 for (uint32_t i = 0; i < count; ++i) { 918 LayoutDeviceIntPoint pt = nsContentUtils::ToWidgetPoint( 919 CSSPoint(aXs[i], aYs[i]), offset, presContext); 920 LayoutDeviceIntPoint radius = LayoutDeviceIntPoint::FromAppUnitsRounded( 921 CSSPoint::ToAppUnits(CSSPoint(aRxs[i], aRys[i])), 922 presContext->AppUnitsPerDevPixel()); 923 924 RefPtr<Touch> t = new Touch(aIdentifiers[i], pt, radius, aRotationAngles[i], 925 aForces[i], aTiltXs[i], aTiltYs[i], aTwists[i]); 926 927 event.mTouches.AppendElement(t); 928 } 929 930 nsEventStatus status = nsEventStatus_eIgnore; 931 if (aToWindow) { 932 RefPtr<PresShell> presShell = presContext->PresShell(); 933 MOZ_TRY(presShell->HandleEvent(presShell->GetRootFrame(), &event, false, 934 &status)); 935 } else if (aAsyncEnabled == AsyncEnabledOption::ASYNC_ENABLED || 936 StaticPrefs::test_events_async_enabled()) { 937 status = widget->DispatchInputEvent(&event).mContentStatus; 938 } else { 939 status = widget->DispatchEvent(&event); 940 } 941 if (aPreventDefault) { 942 *aPreventDefault = (status == nsEventStatus_eConsumeNoDefault); 943 } 944 return NS_OK; 945 } 946 947 static_assert( 948 static_cast<uint32_t>(nsIWidget::Modifiers::CAPS_LOCK) == 949 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CAPS_LOCK), 950 "Need to sync CapsLock value between nsIWidget::Modifiers and " 951 "nsIDOMWindowUtils"); 952 static_assert( 953 static_cast<uint32_t>(nsIWidget::Modifiers::NUM_LOCK) == 954 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_NUM_LOCK), 955 "Need to sync NumLock value between nsIWidget::Modifiers and " 956 "nsIDOMWindowUtils"); 957 static_assert( 958 static_cast<uint32_t>(nsIWidget::Modifiers::SHIFT_L) == 959 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_SHIFT_LEFT), 960 "Need to sync ShiftLeft value between nsIWidget::Modifiers and " 961 "nsIDOMWindowUtils"); 962 static_assert( 963 static_cast<uint32_t>(nsIWidget::Modifiers::SHIFT_R) == 964 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_SHIFT_RIGHT), 965 "Need to sync ShiftRight value between nsIWidget::Modifiers and " 966 "nsIDOMWindowUtils"); 967 static_assert( 968 static_cast<uint32_t>(nsIWidget::Modifiers::CTRL_L) == 969 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CONTROL_LEFT), 970 "Need to sync ControlLeft value between nsIWidget::Modifiers and " 971 "nsIDOMWindowUtils"); 972 static_assert( 973 static_cast<uint32_t>(nsIWidget::Modifiers::CTRL_R) == 974 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_CONTROL_RIGHT), 975 "Need to sync ControlRight value between nsIWidget::Modifiers " 976 "and nsIDOMWindowUtils"); 977 static_assert( 978 static_cast<uint32_t>(nsIWidget::Modifiers::ALT_L) == 979 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_LEFT), 980 "Need to sync AltLeft value between nsIWidget::Modifiers and " 981 "nsIDOMWindowUtils"); 982 static_assert( 983 static_cast<uint32_t>(nsIWidget::Modifiers::ALT_R) == 984 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_RIGHT), 985 "Need to sync AltRight value between nsIWidget::Modifiers and " 986 "nsIDOMWindowUtils"); 987 static_assert( 988 static_cast<uint32_t>(nsIWidget::Modifiers::COMMAND_L) == 989 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_COMMAND_LEFT), 990 "Need to sync CommandLeft value between nsIWidget::Modifiers and " 991 "nsIDOMWindowUtils"); 992 static_assert( 993 static_cast<uint32_t>(nsIWidget::Modifiers::COMMAND_R) == 994 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_COMMAND_RIGHT), 995 "Need to sync CommandRight value between nsIWidget::Modifiers " 996 "and nsIDOMWindowUtils"); 997 static_assert( 998 static_cast<uint32_t>(nsIWidget::Modifiers::HELP) == 999 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_HELP), 1000 "Need to sync Help value between nsIWidget::Modifiers and " 1001 "nsIDOMWindowUtils"); 1002 static_assert( 1003 static_cast<uint32_t>(nsIWidget::Modifiers::ALTGRAPH) == 1004 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_ALT_GRAPH), 1005 "Need to sync AltGraph value between nsIWidget::Modifiers and " 1006 "nsIDOMWindowUtils"); 1007 static_assert( 1008 static_cast<uint32_t>(nsIWidget::Modifiers::FUNCTION) == 1009 static_cast<uint32_t>(nsIDOMWindowUtils::NATIVE_MODIFIER_FUNCTION), 1010 "Need to sync Function value between nsIWidget::Modifiers and " 1011 "nsIDOMWindowUtils"); 1012 static_assert(static_cast<uint32_t>(nsIWidget::Modifiers::NUMERIC_KEY_PAD) == 1013 static_cast<uint32_t>( 1014 nsIDOMWindowUtils::NATIVE_MODIFIER_NUMERIC_KEY_PAD), 1015 "Need to sync NumericKeyPad value between nsIWidget::Modifiers " 1016 "and nsIDOMWindowUtils"); 1017 1018 static nsIWidget::Modifiers GetWidgetModifiers(uint32_t aNativeModifiers) { 1019 nsIWidget::Modifiers widgetModifiers = static_cast<nsIWidget::Modifiers>( 1020 aNativeModifiers & 1021 (nsIWidget::Modifiers::CAPS_LOCK | nsIWidget::Modifiers::NUM_LOCK | 1022 nsIWidget::Modifiers::SHIFT_L | nsIWidget::Modifiers::SHIFT_R | 1023 nsIWidget::Modifiers::CTRL_L | nsIWidget::Modifiers::CTRL_R | 1024 nsIWidget::Modifiers::ALT_L | nsIWidget::Modifiers::ALT_R | 1025 nsIWidget::Modifiers::COMMAND_L | nsIWidget::Modifiers::COMMAND_R | 1026 nsIWidget::Modifiers::HELP | nsIWidget::Modifiers::ALTGRAPH | 1027 nsIWidget::Modifiers::FUNCTION | nsIWidget::Modifiers::NUMERIC_KEY_PAD)); 1028 NS_ASSERTION(static_cast<uint32_t>(widgetModifiers) == aNativeModifiers, 1029 "Invalid value is specified to the native modifiers"); 1030 return widgetModifiers; 1031 } 1032 1033 NS_IMETHODIMP 1034 nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout, 1035 int32_t aNativeKeyCode, 1036 uint32_t aModifiers, 1037 const nsAString& aCharacters, 1038 const nsAString& aUnmodifiedCharacters, 1039 nsISynthesizedEventCallback* aCallback) { 1040 // get the widget to send the event to 1041 nsCOMPtr<nsIWidget> widget = GetWidget(); 1042 if (!widget) { 1043 return NS_ERROR_FAILURE; 1044 } 1045 1046 NS_DispatchToMainThread(NativeInputRunnable::Create( 1047 NewRunnableMethod<int32_t, int32_t, uint32_t, nsString, nsString, 1048 nsISynthesizedEventCallback*>( 1049 "nsIWidget::SynthesizeNativeKeyEvent", widget, 1050 &nsIWidget::SynthesizeNativeKeyEvent, aNativeKeyboardLayout, 1051 aNativeKeyCode, static_cast<uint32_t>(GetWidgetModifiers(aModifiers)), 1052 aCharacters, aUnmodifiedCharacters, aCallback))); 1053 return NS_OK; 1054 } 1055 1056 NS_IMETHODIMP 1057 nsDOMWindowUtils::SendNativeMouseEvent(int32_t aScreenX, int32_t aScreenY, 1058 uint32_t aNativeMessage, int16_t aButton, 1059 uint32_t aModifierFlags, 1060 Element* aElementOnWidget, 1061 nsISynthesizedEventCallback* aCallback) { 1062 // get the widget to send the event to 1063 nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElementOnWidget); 1064 if (!widget) { 1065 return NS_ERROR_FAILURE; 1066 } 1067 1068 nsIWidget::NativeMouseMessage message; 1069 switch (aNativeMessage) { 1070 case NATIVE_MOUSE_MESSAGE_BUTTON_DOWN: 1071 message = nsIWidget::NativeMouseMessage::ButtonDown; 1072 break; 1073 case NATIVE_MOUSE_MESSAGE_BUTTON_UP: 1074 message = nsIWidget::NativeMouseMessage::ButtonUp; 1075 break; 1076 case NATIVE_MOUSE_MESSAGE_MOVE: 1077 message = nsIWidget::NativeMouseMessage::Move; 1078 break; 1079 case NATIVE_MOUSE_MESSAGE_ENTER_WINDOW: 1080 message = nsIWidget::NativeMouseMessage::EnterWindow; 1081 break; 1082 case NATIVE_MOUSE_MESSAGE_LEAVE_WINDOW: 1083 message = nsIWidget::NativeMouseMessage::LeaveWindow; 1084 break; 1085 default: 1086 return NS_ERROR_INVALID_ARG; 1087 } 1088 1089 NS_DispatchToMainThread(NativeInputRunnable::Create( 1090 NewRunnableMethod<LayoutDeviceIntPoint, nsIWidget::NativeMouseMessage, 1091 MouseButton, nsIWidget::Modifiers, 1092 nsISynthesizedEventCallback*>( 1093 "nsIWidget::SynthesizeNativeMouseEvent", widget, 1094 &nsIWidget::SynthesizeNativeMouseEvent, 1095 LayoutDeviceIntPoint(aScreenX, aScreenY), message, 1096 static_cast<MouseButton>(aButton), GetWidgetModifiers(aModifierFlags), 1097 aCallback))); 1098 return NS_OK; 1099 } 1100 1101 NS_IMETHODIMP 1102 nsDOMWindowUtils::SendNativeMouseScrollEvent( 1103 int32_t aScreenX, int32_t aScreenY, uint32_t aNativeMessage, double aDeltaX, 1104 double aDeltaY, double aDeltaZ, uint32_t aModifierFlags, 1105 uint32_t aAdditionalFlags, Element* aElement, 1106 nsISynthesizedEventCallback* aCallback) { 1107 // get the widget to send the event to 1108 nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement); 1109 if (!widget) { 1110 return NS_ERROR_FAILURE; 1111 } 1112 1113 NS_DispatchToMainThread(NativeInputRunnable::Create( 1114 NewRunnableMethod<mozilla::LayoutDeviceIntPoint, uint32_t, double, double, 1115 double, uint32_t, uint32_t, 1116 nsISynthesizedEventCallback*>( 1117 "nsIWidget::SynthesizeNativeMouseScrollEvent", widget, 1118 &nsIWidget::SynthesizeNativeMouseScrollEvent, 1119 LayoutDeviceIntPoint(aScreenX, aScreenY), aNativeMessage, aDeltaX, 1120 aDeltaY, aDeltaZ, aModifierFlags, aAdditionalFlags, aCallback))); 1121 return NS_OK; 1122 } 1123 1124 NS_IMETHODIMP 1125 nsDOMWindowUtils::SendNativeTouchPoint(uint32_t aPointerId, 1126 uint32_t aTouchState, int32_t aScreenX, 1127 int32_t aScreenY, double aPressure, 1128 uint32_t aOrientation, 1129 nsISynthesizedEventCallback* aCallback, 1130 Element* aElement) { 1131 // FYI: This was designed for automated tests, but currently, this is used by 1132 // DevTools to emulate touch events from mouse events in the responsive 1133 // design mode. 1134 1135 nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement); 1136 if (!widget) { 1137 return NS_ERROR_FAILURE; 1138 } 1139 1140 if (aPressure < 0 || aPressure > 1 || aOrientation > 359) { 1141 return NS_ERROR_INVALID_ARG; 1142 } 1143 1144 NS_DispatchToMainThread(NativeInputRunnable::Create( 1145 NewRunnableMethod<uint32_t, nsIWidget::TouchPointerState, 1146 LayoutDeviceIntPoint, double, uint32_t, 1147 nsISynthesizedEventCallback*>( 1148 "nsIWidget::SynthesizeNativeTouchPoint", widget, 1149 &nsIWidget::SynthesizeNativeTouchPoint, aPointerId, 1150 (nsIWidget::TouchPointerState)aTouchState, 1151 LayoutDeviceIntPoint(aScreenX, aScreenY), aPressure, aOrientation, 1152 aCallback))); 1153 return NS_OK; 1154 } 1155 1156 NS_IMETHODIMP 1157 nsDOMWindowUtils::SendNativeTouchpadPinch(uint32_t aEventPhase, float aScale, 1158 int32_t aScreenX, int32_t aScreenY, 1159 int32_t aModifierFlags) { 1160 nsCOMPtr<nsIWidget> widget = GetWidget(); 1161 if (!widget) { 1162 return NS_ERROR_FAILURE; 1163 } 1164 NS_DispatchToMainThread(NativeInputRunnable::Create( 1165 NewRunnableMethod<nsIWidget::TouchpadGesturePhase, float, 1166 LayoutDeviceIntPoint, int32_t>( 1167 "nsIWidget::SynthesizeNativeTouchPadPinch", widget, 1168 &nsIWidget::SynthesizeNativeTouchPadPinch, 1169 (nsIWidget::TouchpadGesturePhase)aEventPhase, aScale, 1170 LayoutDeviceIntPoint(aScreenX, aScreenY), aModifierFlags))); 1171 return NS_OK; 1172 } 1173 1174 NS_IMETHODIMP 1175 nsDOMWindowUtils::SendNativeTouchTap(int32_t aScreenX, int32_t aScreenY, 1176 bool aLongTap, 1177 nsISynthesizedEventCallback* aCallback) { 1178 nsCOMPtr<nsIWidget> widget = GetWidget(); 1179 if (!widget) { 1180 return NS_ERROR_FAILURE; 1181 } 1182 1183 NS_DispatchToMainThread(NativeInputRunnable::Create( 1184 NewRunnableMethod<LayoutDeviceIntPoint, bool, 1185 nsISynthesizedEventCallback*>( 1186 "nsIWidget::SynthesizeNativeTouchTap", widget, 1187 &nsIWidget::SynthesizeNativeTouchTap, 1188 LayoutDeviceIntPoint(aScreenX, aScreenY), aLongTap, aCallback))); 1189 return NS_OK; 1190 } 1191 1192 NS_IMETHODIMP 1193 nsDOMWindowUtils::SendNativePenInput(uint32_t aPointerId, 1194 uint32_t aPointerState, int32_t aScreenX, 1195 int32_t aScreenY, double aPressure, 1196 uint32_t aRotation, int32_t aTiltX, 1197 int32_t aTiltY, int32_t aButton, 1198 nsISynthesizedEventCallback* aCallback, 1199 Element* aElement) { 1200 nsCOMPtr<nsIWidget> widget = GetWidgetForElement(aElement); 1201 if (!widget) { 1202 return NS_ERROR_FAILURE; 1203 } 1204 1205 if (aPressure < 0 || aPressure > 1 || aRotation > 359 || aTiltX < -90 || 1206 aTiltX > 90 || aTiltY < -90 || aTiltY > 90) { 1207 return NS_ERROR_INVALID_ARG; 1208 } 1209 1210 NS_DispatchToMainThread(NativeInputRunnable::Create( 1211 NewRunnableMethod<uint32_t, nsIWidget::TouchPointerState, 1212 LayoutDeviceIntPoint, double, uint32_t, int32_t, 1213 int32_t, int32_t, nsISynthesizedEventCallback*>( 1214 "nsIWidget::SynthesizeNativePenInput", widget, 1215 &nsIWidget::SynthesizeNativePenInput, aPointerId, 1216 (nsIWidget::TouchPointerState)aPointerState, 1217 LayoutDeviceIntPoint(aScreenX, aScreenY), aPressure, aRotation, 1218 aTiltX, aTiltY, aButton, aCallback))); 1219 return NS_OK; 1220 } 1221 1222 NS_IMETHODIMP 1223 nsDOMWindowUtils::SendNativeTouchpadDoubleTap(int32_t aScreenX, 1224 int32_t aScreenY, 1225 int32_t aModifierFlags) { 1226 nsCOMPtr<nsIWidget> widget = GetWidget(); 1227 if (!widget) { 1228 return NS_ERROR_FAILURE; 1229 } 1230 1231 MOZ_ASSERT(aModifierFlags >= 0); 1232 NS_DispatchToMainThread(NativeInputRunnable::Create( 1233 NewRunnableMethod<LayoutDeviceIntPoint, uint32_t>( 1234 "nsIWidget::SynthesizeNativeTouchpadDoubleTap", widget, 1235 &nsIWidget::SynthesizeNativeTouchpadDoubleTap, 1236 LayoutDeviceIntPoint(aScreenX, aScreenY), aModifierFlags))); 1237 return NS_OK; 1238 } 1239 1240 NS_IMETHODIMP 1241 nsDOMWindowUtils::SendNativeTouchpadPan( 1242 uint32_t aEventPhase, int32_t aScreenX, int32_t aScreenY, double aDeltaX, 1243 double aDeltaY, int32_t aModifierFlags, 1244 nsISynthesizedEventCallback* aCallback) { 1245 nsCOMPtr<nsIWidget> widget = GetWidget(); 1246 if (!widget) { 1247 return NS_ERROR_FAILURE; 1248 } 1249 1250 MOZ_ASSERT(aModifierFlags >= 0); 1251 NS_DispatchToMainThread(NativeInputRunnable::Create( 1252 NewRunnableMethod<nsIWidget::TouchpadGesturePhase, LayoutDeviceIntPoint, 1253 double, double, uint32_t, nsISynthesizedEventCallback*>( 1254 "nsIWidget::SynthesizeNativeTouchpadPan", widget, 1255 &nsIWidget::SynthesizeNativeTouchpadPan, 1256 (nsIWidget::TouchpadGesturePhase)aEventPhase, 1257 LayoutDeviceIntPoint(aScreenX, aScreenY), aDeltaX, aDeltaY, 1258 aModifierFlags, aCallback))); 1259 return NS_OK; 1260 } 1261 1262 NS_IMETHODIMP 1263 nsDOMWindowUtils::SuppressAnimation(bool aSuppress) { 1264 nsIWidget* widget = GetWidget(); 1265 if (widget) { 1266 widget->SuppressAnimation(aSuppress); 1267 } 1268 return NS_OK; 1269 } 1270 1271 NS_IMETHODIMP 1272 nsDOMWindowUtils::GetParsedStyleSheets(uint32_t* aSheets) { 1273 RefPtr<Document> doc = GetDocument(); 1274 if (!doc) { 1275 return NS_ERROR_UNEXPECTED; 1276 } 1277 css::Loader* cssLoader = doc->GetExistingCSSLoader(); 1278 if (cssLoader) { 1279 *aSheets = cssLoader->ParsedSheetCount(); 1280 } else { 1281 *aSheets = 0; 1282 } 1283 return NS_OK; 1284 } 1285 1286 NS_IMETHODIMP 1287 nsDOMWindowUtils::ActivateNativeMenuItemAt(const nsAString& indexString) { 1288 // get the widget to send the event to 1289 nsCOMPtr<nsIWidget> widget = GetWidget(); 1290 if (!widget) return NS_ERROR_FAILURE; 1291 1292 return widget->ActivateNativeMenuItemAt(indexString); 1293 } 1294 1295 NS_IMETHODIMP 1296 nsDOMWindowUtils::ForceUpdateNativeMenuAt(const nsAString& indexString) { 1297 // get the widget to send the event to 1298 nsCOMPtr<nsIWidget> widget = GetWidget(); 1299 if (!widget) return NS_ERROR_FAILURE; 1300 1301 return widget->ForceUpdateNativeMenuAt(indexString); 1302 } 1303 1304 NS_IMETHODIMP 1305 nsDOMWindowUtils::GetSelectionAsPlaintext(nsAString& aResult) { 1306 // Get the widget to send the event to. 1307 nsCOMPtr<nsIWidget> widget = GetWidget(); 1308 if (!widget) { 1309 return NS_ERROR_FAILURE; 1310 } 1311 1312 return widget->GetSelectionAsPlaintext(aResult); 1313 } 1314 1315 nsIWidget* nsDOMWindowUtils::GetWidget(nsPoint* aOffset) { 1316 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 1317 if (window) { 1318 nsIDocShell* docShell = window->GetDocShell(); 1319 if (docShell) { 1320 return nsContentUtils::GetWidget(docShell->GetPresShell(), aOffset); 1321 } 1322 } 1323 1324 return nullptr; 1325 } 1326 1327 nsIWidget* nsDOMWindowUtils::GetWidgetForElement(Element* aElement, 1328 nsPoint* aOffset) { 1329 if (!aElement) { 1330 return GetWidget(aOffset); 1331 } 1332 if (Document* doc = aElement->GetUncomposedDoc()) { 1333 if (PresShell* presShell = doc->GetPresShell()) { 1334 nsIFrame* frame = aElement->GetPrimaryFrame(); 1335 if (!frame) { 1336 frame = presShell->GetRootFrame(); 1337 } 1338 if (frame) { 1339 nsPoint offset; 1340 nsIWidget* widget = frame->GetNearestWidget(offset); 1341 if (aOffset) { 1342 *aOffset = offset; 1343 } 1344 return widget; 1345 } 1346 } 1347 } 1348 1349 return nullptr; 1350 } 1351 1352 NS_IMETHODIMP 1353 nsDOMWindowUtils::GarbageCollect(nsICycleCollectorListener* aListener) { 1354 AUTO_PROFILER_LABEL("nsDOMWindowUtils::GarbageCollect", GCCC); 1355 1356 nsJSContext::GarbageCollectNow(JS::GCReason::DOM_UTILS); 1357 nsJSContext::CycleCollectNow(CCReason::API, aListener); 1358 1359 return NS_OK; 1360 } 1361 1362 NS_IMETHODIMP 1363 nsDOMWindowUtils::CycleCollect(nsICycleCollectorListener* aListener) { 1364 nsJSContext::CycleCollectNow(CCReason::API, aListener); 1365 return NS_OK; 1366 } 1367 1368 static bool ParseGCReason(const nsACString& aStr, JS::GCReason* aReason, 1369 JS::GCReason aDefault) { 1370 if (aStr.IsEmpty()) { 1371 *aReason = aDefault; 1372 return true; 1373 } 1374 #define CHECK_REASON(name, _) \ 1375 if (aStr.EqualsIgnoreCase(#name)) { \ 1376 *aReason = JS::GCReason::name; \ 1377 return true; \ 1378 } 1379 GCREASONS(CHECK_REASON); 1380 return false; 1381 } 1382 1383 NS_IMETHODIMP 1384 nsDOMWindowUtils::RunNextCollectorTimer(const nsACString& aReason) { 1385 JS::GCReason reason; 1386 if (!ParseGCReason(aReason, &reason, JS::GCReason::DOM_WINDOW_UTILS)) { 1387 return NS_ERROR_INVALID_ARG; 1388 } 1389 1390 nsJSContext::RunNextCollectorTimer(reason); 1391 1392 return NS_OK; 1393 } 1394 1395 NS_IMETHODIMP 1396 nsDOMWindowUtils::PokeGC(const nsACString& aReason) { 1397 JS::GCReason reason; 1398 if (!ParseGCReason(aReason, &reason, JS::GCReason::DOM_WINDOW_UTILS)) { 1399 return NS_ERROR_INVALID_ARG; 1400 } 1401 1402 nsJSContext::PokeGC(reason, nullptr); 1403 1404 return NS_OK; 1405 } 1406 1407 NS_IMETHODIMP 1408 nsDOMWindowUtils::SendSimpleGestureEvent(const nsAString& aType, float aX, 1409 float aY, uint32_t aDirection, 1410 double aDelta, int32_t aModifiers, 1411 uint32_t aClickCount) { 1412 // get the widget to send the event to 1413 nsPoint offset; 1414 nsCOMPtr<nsIWidget> widget = GetWidget(&offset); 1415 if (!widget) return NS_ERROR_FAILURE; 1416 1417 EventMessage msg; 1418 if (aType.EqualsLiteral("MozSwipeGestureMayStart")) { 1419 msg = eSwipeGestureMayStart; 1420 } else if (aType.EqualsLiteral("MozSwipeGestureStart")) { 1421 msg = eSwipeGestureStart; 1422 } else if (aType.EqualsLiteral("MozSwipeGestureUpdate")) { 1423 msg = eSwipeGestureUpdate; 1424 } else if (aType.EqualsLiteral("MozSwipeGestureEnd")) { 1425 msg = eSwipeGestureEnd; 1426 } else if (aType.EqualsLiteral("MozSwipeGesture")) { 1427 msg = eSwipeGesture; 1428 } else if (aType.EqualsLiteral("MozMagnifyGestureStart")) { 1429 msg = eMagnifyGestureStart; 1430 } else if (aType.EqualsLiteral("MozMagnifyGestureUpdate")) { 1431 msg = eMagnifyGestureUpdate; 1432 } else if (aType.EqualsLiteral("MozMagnifyGesture")) { 1433 msg = eMagnifyGesture; 1434 } else if (aType.EqualsLiteral("MozRotateGestureStart")) { 1435 msg = eRotateGestureStart; 1436 } else if (aType.EqualsLiteral("MozRotateGestureUpdate")) { 1437 msg = eRotateGestureUpdate; 1438 } else if (aType.EqualsLiteral("MozRotateGesture")) { 1439 msg = eRotateGesture; 1440 } else if (aType.EqualsLiteral("MozTapGesture")) { 1441 msg = eTapGesture; 1442 } else if (aType.EqualsLiteral("MozPressTapGesture")) { 1443 msg = ePressTapGesture; 1444 } else if (aType.EqualsLiteral("MozEdgeUIStarted")) { 1445 msg = eEdgeUIStarted; 1446 } else if (aType.EqualsLiteral("MozEdgeUICanceled")) { 1447 msg = eEdgeUICanceled; 1448 } else if (aType.EqualsLiteral("MozEdgeUICompleted")) { 1449 msg = eEdgeUICompleted; 1450 } else { 1451 return NS_ERROR_FAILURE; 1452 } 1453 1454 WidgetSimpleGestureEvent event(true, msg, widget); 1455 event.mModifiers = nsContentUtils::GetWidgetModifiers(aModifiers); 1456 event.mDirection = aDirection; 1457 event.mDelta = aDelta; 1458 event.mClickCount = aClickCount; 1459 1460 nsPresContext* presContext = GetPresContext(); 1461 if (!presContext) return NS_ERROR_FAILURE; 1462 1463 event.mRefPoint = 1464 nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, presContext); 1465 1466 widget->DispatchEvent(&event); 1467 return NS_OK; 1468 } 1469 1470 NS_IMETHODIMP 1471 nsDOMWindowUtils::ElementFromPoint(float aX, float aY, 1472 bool aIgnoreRootScrollFrame, 1473 bool aFlushLayout, Element** aReturn) { 1474 nsCOMPtr<Document> doc = GetDocument(); 1475 NS_ENSURE_STATE(doc); 1476 1477 RefPtr<Element> el = doc->ElementFromPointHelper( 1478 aX, aY, aIgnoreRootScrollFrame, aFlushLayout, ViewportType::Layout); 1479 el.forget(aReturn); 1480 return NS_OK; 1481 } 1482 1483 NS_IMETHODIMP 1484 nsDOMWindowUtils::NodesFromRect(float aX, float aY, float aTopSize, 1485 float aRightSize, float aBottomSize, 1486 float aLeftSize, bool aIgnoreRootScrollFrame, 1487 bool aFlushLayout, bool aOnlyVisible, 1488 float aVisibleThreshold, 1489 nsINodeList** aReturn) { 1490 RefPtr<Document> doc = GetDocument(); 1491 NS_ENSURE_STATE(doc); 1492 1493 auto list = MakeRefPtr<nsSimpleContentList>(doc); 1494 1495 // The visible threshold was omitted or given a zero value (which makes no 1496 // sense), so give a reasonable default. 1497 if (aVisibleThreshold == 0.0f) { 1498 aVisibleThreshold = 1.0f; 1499 } 1500 1501 AutoTArray<RefPtr<nsINode>, 8> nodes; 1502 doc->NodesFromRect(aX, aY, aTopSize, aRightSize, aBottomSize, aLeftSize, 1503 aIgnoreRootScrollFrame, aFlushLayout, aOnlyVisible, 1504 aVisibleThreshold, nodes); 1505 list->SetCapacity(nodes.Length()); 1506 for (auto& node : nodes) { 1507 list->AppendElement(node->AsContent()); 1508 } 1509 1510 list.forget(aReturn); 1511 return NS_OK; 1512 } 1513 1514 NS_IMETHODIMP 1515 nsDOMWindowUtils::GetTranslationNodes(nsINode* aRoot, 1516 nsITranslationNodeList** aRetVal) { 1517 NS_ENSURE_ARG_POINTER(aRetVal); 1518 nsCOMPtr<nsIContent> root = do_QueryInterface(aRoot); 1519 NS_ENSURE_STATE(root); 1520 nsCOMPtr<Document> doc = GetDocument(); 1521 NS_ENSURE_STATE(doc); 1522 1523 if (root->OwnerDoc() != doc) { 1524 return NS_ERROR_DOM_WRONG_DOCUMENT_ERR; 1525 } 1526 1527 nsTHashSet<nsIContent*> translationNodesHash(500); 1528 RefPtr<nsTranslationNodeList> list = new nsTranslationNodeList; 1529 1530 uint32_t limit = 15000; 1531 1532 // We begin iteration with content->GetNextNode because we want to explicitly 1533 // skip the root tag from being a translation node. 1534 nsIContent* content = root; 1535 while ((limit > 0) && (content = content->GetNextNode(root))) { 1536 if (!content->IsHTMLElement()) { 1537 continue; 1538 } 1539 1540 // Skip elements that usually contain non-translatable text content. 1541 if (content->IsAnyOfHTMLElements(nsGkAtoms::script, nsGkAtoms::iframe, 1542 nsGkAtoms::frameset, nsGkAtoms::frame, 1543 nsGkAtoms::code, nsGkAtoms::noscript, 1544 nsGkAtoms::style)) { 1545 continue; 1546 } 1547 1548 // An element is a translation node if it contains 1549 // at least one text node that has meaningful data 1550 // for translation 1551 for (nsIContent* child = content->GetFirstChild(); child; 1552 child = child->GetNextSibling()) { 1553 if (child->IsText() && child->GetAsText()->HasTextForTranslation()) { 1554 translationNodesHash.Insert(content); 1555 1556 nsIFrame* frame = content->GetPrimaryFrame(); 1557 bool isTranslationRoot = frame && frame->IsBlockFrameOrSubclass(); 1558 if (!isTranslationRoot) { 1559 // If an element is not a block element, it still 1560 // can be considered a translation root if the parent 1561 // of this element didn't make into the list of nodes 1562 // to be translated. 1563 bool parentInList = false; 1564 nsIContent* parent = content->GetParent(); 1565 if (parent) { 1566 parentInList = translationNodesHash.Contains(parent); 1567 } 1568 isTranslationRoot = !parentInList; 1569 } 1570 1571 list->AppendElement(content, isTranslationRoot); 1572 --limit; 1573 break; 1574 } 1575 } 1576 } 1577 1578 *aRetVal = list.forget().take(); 1579 return NS_OK; 1580 } 1581 1582 static already_AddRefed<DataSourceSurface> CanvasToDataSourceSurface( 1583 HTMLCanvasElement* aCanvas) { 1584 MOZ_ASSERT(aCanvas); 1585 SurfaceFromElementResult result = nsLayoutUtils::SurfaceFromElement(aCanvas); 1586 const RefPtr<SourceSurface> surf = result.GetSourceSurface(); 1587 if (!surf) { 1588 return nullptr; 1589 } 1590 return surf->GetDataSurface(); 1591 } 1592 1593 NS_IMETHODIMP 1594 nsDOMWindowUtils::CompareCanvases(nsISupports* aCanvas1, nsISupports* aCanvas2, 1595 uint32_t* aMaxDifference, uint32_t* retVal) { 1596 nsCOMPtr<nsIContent> contentCanvas1 = do_QueryInterface(aCanvas1); 1597 nsCOMPtr<nsIContent> contentCanvas2 = do_QueryInterface(aCanvas2); 1598 auto* canvas1 = HTMLCanvasElement::FromNodeOrNull(contentCanvas1); 1599 auto* canvas2 = HTMLCanvasElement::FromNodeOrNull(contentCanvas2); 1600 1601 if (NS_WARN_IF(!canvas1) || NS_WARN_IF(!canvas2)) { 1602 return NS_ERROR_FAILURE; 1603 } 1604 1605 RefPtr<DataSourceSurface> img1 = CanvasToDataSourceSurface(canvas1); 1606 RefPtr<DataSourceSurface> img2 = CanvasToDataSourceSurface(canvas2); 1607 1608 if (NS_WARN_IF(!img1) || NS_WARN_IF(!img2) || 1609 NS_WARN_IF(img1->GetSize() != img2->GetSize())) { 1610 return NS_ERROR_FAILURE; 1611 } 1612 1613 if (img1->Equals(img2)) { 1614 // They point to the same underlying content. 1615 return NS_OK; 1616 } 1617 1618 DataSourceSurface::ScopedMap map1(img1, DataSourceSurface::READ); 1619 DataSourceSurface::ScopedMap map2(img2, DataSourceSurface::READ); 1620 1621 if (NS_WARN_IF(!map1.IsMapped()) || NS_WARN_IF(!map2.IsMapped())) { 1622 return NS_ERROR_FAILURE; 1623 } 1624 1625 int v; 1626 IntSize size = img1->GetSize(); 1627 int32_t stride1 = map1.GetStride(); 1628 int32_t stride2 = map2.GetStride(); 1629 1630 // we can optimize for the common all-pass case 1631 if (stride1 == stride2 && stride1 == size.width * 4) { 1632 v = memcmp(map1.GetData(), map2.GetData(), size.width * size.height * 4); 1633 if (v == 0) { 1634 if (aMaxDifference) *aMaxDifference = 0; 1635 *retVal = 0; 1636 return NS_OK; 1637 } 1638 } 1639 1640 uint32_t dc = 0; 1641 uint32_t different = 0; 1642 1643 for (int j = 0; j < size.height; j++) { 1644 unsigned char* p1 = map1.GetData() + j * stride1; 1645 unsigned char* p2 = map2.GetData() + j * stride2; 1646 v = memcmp(p1, p2, size.width * 4); 1647 1648 if (v) { 1649 for (int i = 0; i < size.width; i++) { 1650 if (*(uint32_t*)p1 != *(uint32_t*)p2) { 1651 different++; 1652 1653 dc = std::max((uint32_t)abs(p1[0] - p2[0]), dc); 1654 dc = std::max((uint32_t)abs(p1[1] - p2[1]), dc); 1655 dc = std::max((uint32_t)abs(p1[2] - p2[2]), dc); 1656 dc = std::max((uint32_t)abs(p1[3] - p2[3]), dc); 1657 } 1658 1659 p1 += 4; 1660 p2 += 4; 1661 } 1662 } 1663 } 1664 1665 if (aMaxDifference) *aMaxDifference = dc; 1666 1667 *retVal = different; 1668 return NS_OK; 1669 } 1670 1671 NS_IMETHODIMP 1672 nsDOMWindowUtils::GetIsMozAfterPaintPending(bool* aResult) { 1673 NS_ENSURE_ARG_POINTER(aResult); 1674 *aResult = false; 1675 nsPresContext* presContext = GetPresContext(); 1676 if (!presContext) return NS_OK; 1677 *aResult = presContext->IsDOMPaintEventPending(); 1678 return NS_OK; 1679 } 1680 1681 NS_IMETHODIMP 1682 nsDOMWindowUtils::GetIsWindowFullyOccluded(bool* aResult) { 1683 NS_ENSURE_ARG_POINTER(aResult); 1684 *aResult = false; 1685 if (nsIWidget* widget = GetWidget()) { 1686 *aResult = widget->IsFullyOccluded(); 1687 } 1688 return NS_OK; 1689 } 1690 1691 NS_IMETHODIMP 1692 nsDOMWindowUtils::GetIsCompositorPaused(bool* aResult) { 1693 NS_ENSURE_ARG_POINTER(aResult); 1694 *aResult = false; 1695 CompositorBridgeChild* cbc = GetCompositorBridge(); 1696 if (cbc) { 1697 *aResult = cbc->IsPaused(); 1698 } 1699 return NS_OK; 1700 } 1701 1702 NS_IMETHODIMP 1703 nsDOMWindowUtils::GetIsInputTaskManagerSuspended(bool* aResult) { 1704 *aResult = InputTaskManager::Get()->IsSuspended(); 1705 return NS_OK; 1706 } 1707 1708 NS_IMETHODIMP 1709 nsDOMWindowUtils::DisableNonTestMouseEvents(bool aDisable) { 1710 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 1711 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 1712 nsIDocShell* docShell = window->GetDocShell(); 1713 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 1714 PresShell* presShell = docShell->GetPresShell(); 1715 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); 1716 presShell->DisableNonTestMouseEvents(aDisable); 1717 return NS_OK; 1718 } 1719 1720 NS_IMETHODIMP 1721 nsDOMWindowUtils::SuppressEventHandling(bool aSuppress) { 1722 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 1723 NS_ENSURE_STATE(window); 1724 1725 if (aSuppress) { 1726 window->SuppressEventHandling(); 1727 } else { 1728 window->UnsuppressEventHandling(); 1729 } 1730 1731 return NS_OK; 1732 } 1733 1734 static nsresult getScrollXYAppUnits(const nsWeakPtr& aWindow, bool aFlushLayout, 1735 nsPoint& aScrollPos) { 1736 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(aWindow); 1737 nsCOMPtr<Document> doc = window ? window->GetExtantDoc() : nullptr; 1738 NS_ENSURE_STATE(doc); 1739 1740 if (aFlushLayout) { 1741 doc->FlushPendingNotifications(FlushType::Layout); 1742 } 1743 1744 if (PresShell* presShell = doc->GetPresShell()) { 1745 ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame(); 1746 if (sf) { 1747 aScrollPos = sf->GetScrollPosition(); 1748 } 1749 } 1750 return NS_OK; 1751 } 1752 1753 NS_IMETHODIMP 1754 nsDOMWindowUtils::GetScrollXY(bool aFlushLayout, int32_t* aScrollX, 1755 int32_t* aScrollY) { 1756 nsPoint scrollPos(0, 0); 1757 nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos); 1758 NS_ENSURE_SUCCESS(rv, rv); 1759 *aScrollX = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.x); 1760 *aScrollY = nsPresContext::AppUnitsToIntCSSPixels(scrollPos.y); 1761 1762 return NS_OK; 1763 } 1764 1765 NS_IMETHODIMP 1766 nsDOMWindowUtils::GetScrollXYFloat(bool aFlushLayout, float* aScrollX, 1767 float* aScrollY) { 1768 nsPoint scrollPos(0, 0); 1769 nsresult rv = getScrollXYAppUnits(mWindow, aFlushLayout, scrollPos); 1770 NS_ENSURE_SUCCESS(rv, rv); 1771 *aScrollX = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.x); 1772 *aScrollY = nsPresContext::AppUnitsToFloatCSSPixels(scrollPos.y); 1773 1774 return NS_OK; 1775 } 1776 1777 NS_IMETHODIMP 1778 nsDOMWindowUtils::ScrollToVisual(float aOffsetX, float aOffsetY, 1779 int32_t aUpdateType, int32_t aScrollMode) { 1780 nsCOMPtr<Document> doc = GetDocument(); 1781 NS_ENSURE_STATE(doc); 1782 1783 nsPresContext* presContext = doc->GetPresContext(); 1784 NS_ENSURE_TRUE(presContext, NS_ERROR_NOT_AVAILABLE); 1785 1786 // This should only be called on the root content document. 1787 NS_ENSURE_TRUE(presContext->IsRootContentDocumentCrossProcess(), 1788 NS_ERROR_INVALID_ARG); 1789 1790 ScrollContainerFrame* sf = 1791 presContext->PresShell()->GetRootScrollContainerFrame(); 1792 NS_ENSURE_TRUE(sf, NS_ERROR_NOT_AVAILABLE); 1793 1794 FrameMetrics::ScrollOffsetUpdateType updateType; 1795 switch (aUpdateType) { 1796 case UPDATE_TYPE_RESTORE: 1797 updateType = FrameMetrics::eRestore; 1798 break; 1799 case UPDATE_TYPE_MAIN_THREAD: 1800 updateType = FrameMetrics::eMainThread; 1801 break; 1802 default: 1803 return NS_ERROR_INVALID_ARG; 1804 } 1805 1806 ScrollBehavior scrollBehavior; 1807 switch (aScrollMode) { 1808 case SCROLL_MODE_INSTANT: 1809 scrollBehavior = ScrollBehavior::Instant; 1810 break; 1811 case SCROLL_MODE_SMOOTH: 1812 scrollBehavior = ScrollBehavior::Smooth; 1813 break; 1814 default: 1815 return NS_ERROR_INVALID_ARG; 1816 } 1817 1818 presContext->PresShell()->ScrollToVisual( 1819 CSSPoint::ToAppUnits(CSSPoint(aOffsetX, aOffsetY)), updateType, 1820 sf->ScrollModeForScrollBehavior(scrollBehavior)); 1821 1822 return NS_OK; 1823 } 1824 1825 NS_IMETHODIMP 1826 nsDOMWindowUtils::GetVisualViewportOffsetRelativeToLayoutViewport( 1827 float* aOffsetX, float* aOffsetY) { 1828 *aOffsetX = 0; 1829 *aOffsetY = 0; 1830 1831 nsCOMPtr<Document> doc = GetDocument(); 1832 NS_ENSURE_STATE(doc); 1833 1834 PresShell* presShell = doc->GetPresShell(); 1835 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE); 1836 1837 nsPoint offset = presShell->GetVisualViewportOffsetRelativeToLayoutViewport(); 1838 *aOffsetX = nsPresContext::AppUnitsToFloatCSSPixels(offset.x); 1839 *aOffsetY = nsPresContext::AppUnitsToFloatCSSPixels(offset.y); 1840 1841 return NS_OK; 1842 } 1843 1844 NS_IMETHODIMP 1845 nsDOMWindowUtils::GetVisualViewportOffset(int32_t* aOffsetX, 1846 int32_t* aOffsetY) { 1847 *aOffsetX = 0; 1848 *aOffsetY = 0; 1849 1850 nsCOMPtr<Document> doc = GetDocument(); 1851 NS_ENSURE_STATE(doc); 1852 1853 PresShell* presShell = doc->GetPresShell(); 1854 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE); 1855 1856 nsPoint offset = presShell->GetVisualViewportOffset(); 1857 *aOffsetX = nsPresContext::AppUnitsToIntCSSPixels(offset.x); 1858 *aOffsetY = nsPresContext::AppUnitsToIntCSSPixels(offset.y); 1859 1860 return NS_OK; 1861 } 1862 1863 NS_IMETHODIMP 1864 nsDOMWindowUtils::TransformRectLayoutToVisual(float aX, float aY, float aWidth, 1865 float aHeight, 1866 DOMRect** aResult) { 1867 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 1868 NS_ENSURE_STATE(window); 1869 1870 PresShell* presShell = GetPresShell(); 1871 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE); 1872 1873 CSSRect rect(aX, aY, aWidth, aHeight); 1874 rect = ViewportUtils::DocumentRelativeLayoutToVisual(rect, presShell); 1875 1876 RefPtr<DOMRect> outRect = new DOMRect(window); 1877 outRect->SetRect(rect.x, rect.y, rect.width, rect.height); 1878 outRect.forget(aResult); 1879 return NS_OK; 1880 } 1881 1882 Result<mozilla::LayoutDeviceRect, nsresult> nsDOMWindowUtils::ConvertTo( 1883 float aX, float aY, float aWidth, float aHeight, CoordsType aCoordsType) { 1884 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 1885 if (!window) { 1886 return Err(NS_ERROR_NOT_AVAILABLE); 1887 } 1888 1889 PresShell* presShell = GetPresShell(); 1890 if (!presShell) { 1891 return Err(NS_ERROR_NOT_AVAILABLE); 1892 } 1893 1894 nsCOMPtr<nsIWidget> widget = GetWidget(); 1895 if (!widget) { 1896 return Err(NS_ERROR_NOT_AVAILABLE); 1897 } 1898 1899 // Note that if the document is NOT in OOP iframes, i.e. it's in the top level 1900 // content subtree in the same process, 1901 // nsIWidget::WidgetToTopLevelWidgetTransform() doesn't include the desktop 1902 // zoom value, so for documents in the top level content document subtree, 1903 // this ViewportUtils::DocumentRelativeLayoutToVisual call applies the desktop 1904 // zoom value via PresShell::GetResolution() in the function. 1905 CSSRect rect(aX, aY, aWidth, aHeight); 1906 rect = ViewportUtils::DocumentRelativeLayoutToVisual(rect, presShell); 1907 1908 nsPresContext* presContext = presShell->GetPresContext(); 1909 MOZ_ASSERT(presContext); 1910 1911 // For OOP iframe documents, we don't have desktop zoom value specifically in 1912 // each iframe documents (i.e. the in-process root presshell's resolution is 1913 // 1.0), instead nsIWidget::WidgetToTopLevelWidgetTransform() includes the 1914 // desktop zoom scale value along with translations by ancestor scroll 1915 // containers, ancestor CSS transforms, etc. 1916 nsRect appUnitsRect = CSSPixel::ToAppUnits(rect); 1917 LayoutDeviceRect devPixelsRect = LayoutDeviceRect::FromAppUnits( 1918 appUnitsRect, presContext->AppUnitsPerDevPixel()); 1919 devPixelsRect = 1920 widget->WidgetToTopLevelWidgetTransform().TransformBounds(devPixelsRect); 1921 1922 switch (aCoordsType) { 1923 case CoordsType::Screen: 1924 devPixelsRect += widget->TopLevelWidgetToScreenOffset(); 1925 break; 1926 case CoordsType::TopLevelWidget: 1927 // There's nothing to do. 1928 break; 1929 } 1930 return devPixelsRect; 1931 } 1932 1933 NS_IMETHODIMP 1934 nsDOMWindowUtils::ToScreenRectInCSSUnits(float aX, float aY, float aWidth, 1935 float aHeight, DOMRect** aResult) { 1936 LayoutDeviceRect devRect = 1937 MOZ_TRY(ConvertTo(aX, aY, aWidth, aHeight, CoordsType::Screen)); 1938 1939 nsPresContext* presContext = GetPresContext(); 1940 MOZ_ASSERT(presContext); 1941 1942 // We want to return the screen rect in CSS units of the browser chrome. 1943 // 1944 // TODO(emilio): It'd be cleaner to convert callers to use plain toScreenRect, 1945 // and perform the screen -> CSS rect in the parent process instead, probably. 1946 const nsRect appUnitsRect = LayoutDeviceRect::ToAppUnits( 1947 devRect, 1948 presContext->DeviceContext()->AppUnitsPerDevPixelInTopLevelChromePage()); 1949 1950 RefPtr<DOMRect> outRect = new DOMRect(mWindow); 1951 outRect->SetLayoutRect(appUnitsRect); 1952 1953 outRect.forget(aResult); 1954 return NS_OK; 1955 } 1956 1957 NS_IMETHODIMP 1958 nsDOMWindowUtils::ToScreenRect(float aX, float aY, float aWidth, float aHeight, 1959 DOMRect** aResult) { 1960 LayoutDeviceRect devPixelsRect = 1961 MOZ_TRY(ConvertTo(aX, aY, aWidth, aHeight, CoordsType::Screen)); 1962 1963 ScreenRect rect = ViewAs<ScreenPixel>( 1964 devPixelsRect, PixelCastJustification::ScreenIsParentLayerForRoot); 1965 1966 RefPtr<DOMRect> outRect = new DOMRect(mWindow); 1967 outRect->SetRect(rect.x, rect.y, rect.width, rect.height); 1968 outRect.forget(aResult); 1969 return NS_OK; 1970 } 1971 1972 NS_IMETHODIMP 1973 nsDOMWindowUtils::ToTopLevelWidgetRect(float aX, float aY, float aWidth, 1974 float aHeight, DOMRect** aResult) { 1975 LayoutDeviceRect rect = 1976 MOZ_TRY(ConvertTo(aX, aY, aWidth, aHeight, CoordsType::TopLevelWidget)); 1977 1978 RefPtr<DOMRect> outRect = new DOMRect(mWindow); 1979 outRect->SetRect(rect.x, rect.y, rect.width, rect.height); 1980 outRect.forget(aResult); 1981 return NS_OK; 1982 } 1983 1984 NS_IMETHODIMP 1985 nsDOMWindowUtils::ConvertFromParentProcessWidgetToLocal(float aX, float aY, 1986 float aWidth, 1987 float aHeight, 1988 DOMRect** aResult) { 1989 if (!XRE_IsContentProcess()) { 1990 return NS_ERROR_NOT_AVAILABLE; 1991 } 1992 1993 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 1994 if (!window) { 1995 return NS_ERROR_NOT_AVAILABLE; 1996 } 1997 1998 nsCOMPtr<nsIWidget> widget = GetWidget(); 1999 if (!widget) { 2000 return NS_ERROR_NOT_AVAILABLE; 2001 } 2002 2003 LayoutDeviceRect devPixelsRect = LayoutDeviceRect(aX, aY, aWidth, aHeight); 2004 2005 Maybe<LayoutDeviceToLayoutDeviceMatrix4x4> inverse = 2006 widget->WidgetToTopLevelWidgetTransform().MaybeInverse(); 2007 if (inverse) { 2008 Maybe<LayoutDeviceRect> rect = 2009 UntransformBy(*inverse, devPixelsRect, LayoutDeviceRect::MaxIntRect()); 2010 if (rect) { 2011 RefPtr<DOMRect> outRect = new DOMRect(mWindow); 2012 outRect->SetRect(rect->x, rect->y, rect->width, rect->height); 2013 outRect.forget(aResult); 2014 return NS_OK; 2015 } 2016 } 2017 2018 RefPtr<DOMRect> outRect = new DOMRect(mWindow); 2019 outRect->SetRect(0, 0, 0, 0); 2020 outRect.forget(aResult); 2021 return NS_ERROR_NOT_AVAILABLE; 2022 } 2023 2024 NS_IMETHODIMP 2025 nsDOMWindowUtils::SetDynamicToolbarMaxHeight(uint32_t aHeightInScreen) { 2026 if (aHeightInScreen > INT32_MAX) { 2027 return NS_ERROR_INVALID_ARG; 2028 } 2029 2030 RefPtr<nsPresContext> presContext = GetPresContext(); 2031 if (!presContext) { 2032 return NS_OK; 2033 } 2034 2035 MOZ_ASSERT(presContext->IsRootContentDocumentCrossProcess()); 2036 2037 presContext->SetDynamicToolbarMaxHeight(ScreenIntCoord(aHeightInScreen)); 2038 2039 return NS_OK; 2040 } 2041 2042 NS_IMETHODIMP 2043 nsDOMWindowUtils::GetScrollbarSize(bool aFlushLayout, int32_t* aWidth, 2044 int32_t* aHeight) { 2045 *aWidth = 0; 2046 *aHeight = 0; 2047 2048 nsCOMPtr<Document> doc = GetDocument(); 2049 NS_ENSURE_STATE(doc); 2050 2051 if (aFlushLayout) { 2052 doc->FlushPendingNotifications(FlushType::Layout); 2053 } 2054 2055 PresShell* presShell = doc->GetPresShell(); 2056 NS_ENSURE_TRUE(presShell, NS_ERROR_NOT_AVAILABLE); 2057 2058 ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame(); 2059 NS_ENSURE_TRUE(sf, NS_OK); 2060 2061 nsMargin sizes = sf->GetActualScrollbarSizes(); 2062 *aWidth = nsPresContext::AppUnitsToIntCSSPixels(sizes.LeftRight()); 2063 *aHeight = nsPresContext::AppUnitsToIntCSSPixels(sizes.TopBottom()); 2064 2065 return NS_OK; 2066 } 2067 2068 NS_IMETHODIMP 2069 nsDOMWindowUtils::GetBoundsWithoutFlushing(Element* aElement, 2070 DOMRect** aResult) { 2071 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 2072 NS_ENSURE_STATE(window); 2073 2074 NS_ENSURE_ARG_POINTER(aElement); 2075 2076 RefPtr<DOMRect> rect = new DOMRect(window); 2077 nsIFrame* frame = aElement->GetPrimaryFrame(); 2078 2079 if (frame) { 2080 nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion( 2081 frame, nsLayoutUtils::GetContainingBlockForClientRect(frame), 2082 nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms); 2083 rect->SetLayoutRect(r); 2084 } 2085 2086 rect.forget(aResult); 2087 return NS_OK; 2088 } 2089 2090 NS_IMETHODIMP 2091 nsDOMWindowUtils::NeedsFlush(int32_t aFlushType, bool* aResult) { 2092 MOZ_ASSERT(aResult); 2093 2094 nsCOMPtr<Document> doc = GetDocument(); 2095 NS_ENSURE_STATE(doc); 2096 2097 PresShell* presShell = doc->GetPresShell(); 2098 NS_ENSURE_STATE(presShell); 2099 2100 FlushType flushType; 2101 switch (aFlushType) { 2102 case FLUSH_STYLE: 2103 flushType = FlushType::Style; 2104 break; 2105 2106 case FLUSH_LAYOUT: 2107 flushType = FlushType::Layout; 2108 break; 2109 2110 default: 2111 return NS_ERROR_INVALID_ARG; 2112 } 2113 2114 *aResult = presShell->NeedFlush(flushType); 2115 return NS_OK; 2116 } 2117 2118 NS_IMETHODIMP 2119 nsDOMWindowUtils::FlushLayoutWithoutThrottledAnimations() { 2120 if (nsCOMPtr<Document> doc = GetDocument()) { 2121 doc->FlushPendingNotifications( 2122 ChangesToFlush(FlushType::Layout, /* aFlushAnimations = */ false, 2123 /* aUpdateRelevancy = */ true)); 2124 } 2125 return NS_OK; 2126 } 2127 2128 NS_IMETHODIMP 2129 nsDOMWindowUtils::GetRootBounds(DOMRect** aResult) { 2130 Document* doc = GetDocument(); 2131 NS_ENSURE_STATE(doc); 2132 2133 nsRect bounds(0, 0, 0, 0); 2134 PresShell* presShell = doc->GetPresShell(); 2135 if (presShell) { 2136 ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame(); 2137 if (sf) { 2138 bounds = sf->GetScrollRange(); 2139 bounds.SetWidth(bounds.Width() + sf->GetScrollPortRect().Width()); 2140 bounds.SetHeight(bounds.Height() + sf->GetScrollPortRect().Height()); 2141 } else if (presShell->GetRootFrame()) { 2142 bounds = presShell->GetRootFrame()->GetRect(); 2143 } 2144 } 2145 2146 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 2147 RefPtr<DOMRect> rect = new DOMRect(window); 2148 rect->SetRect(nsPresContext::AppUnitsToFloatCSSPixels(bounds.x), 2149 nsPresContext::AppUnitsToFloatCSSPixels(bounds.y), 2150 nsPresContext::AppUnitsToFloatCSSPixels(bounds.Width()), 2151 nsPresContext::AppUnitsToFloatCSSPixels(bounds.Height())); 2152 rect.forget(aResult); 2153 return NS_OK; 2154 } 2155 2156 NS_IMETHODIMP 2157 nsDOMWindowUtils::GetIMEIsOpen(bool* aState) { 2158 NS_ENSURE_ARG_POINTER(aState); 2159 2160 nsCOMPtr<nsIWidget> widget = GetWidget(); 2161 if (!widget) return NS_ERROR_FAILURE; 2162 2163 // Open state should not be available when IME is not enabled. 2164 InputContext context = widget->GetInputContext(); 2165 if (context.mIMEState.mEnabled != IMEEnabled::Enabled) { 2166 return NS_ERROR_NOT_AVAILABLE; 2167 } 2168 2169 if (context.mIMEState.mOpen == IMEState::OPEN_STATE_NOT_SUPPORTED) { 2170 return NS_ERROR_NOT_IMPLEMENTED; 2171 } 2172 *aState = (context.mIMEState.mOpen == IMEState::OPEN); 2173 return NS_OK; 2174 } 2175 2176 NS_IMETHODIMP 2177 nsDOMWindowUtils::GetIMEStatus(uint32_t* aState) { 2178 NS_ENSURE_ARG_POINTER(aState); 2179 2180 nsCOMPtr<nsIWidget> widget = GetWidget(); 2181 if (!widget) return NS_ERROR_FAILURE; 2182 2183 InputContext context = widget->GetInputContext(); 2184 *aState = static_cast<uint32_t>(context.mIMEState.mEnabled); 2185 return NS_OK; 2186 } 2187 2188 NS_IMETHODIMP 2189 nsDOMWindowUtils::GetInputContextURI(nsIURI** aURI) { 2190 NS_ENSURE_ARG_POINTER(aURI); 2191 2192 nsCOMPtr<nsIWidget> widget = GetWidget(); 2193 if (!widget) { 2194 return NS_ERROR_FAILURE; 2195 } 2196 2197 nsCOMPtr<nsIURI> documentURI = widget->GetInputContext().mURI; 2198 documentURI.forget(aURI); 2199 return NS_OK; 2200 } 2201 2202 NS_IMETHODIMP 2203 nsDOMWindowUtils::GetInputContextOrigin(uint32_t* aOrigin) { 2204 NS_ENSURE_ARG_POINTER(aOrigin); 2205 2206 nsCOMPtr<nsIWidget> widget = GetWidget(); 2207 if (!widget) { 2208 return NS_ERROR_FAILURE; 2209 } 2210 2211 InputContext context = widget->GetInputContext(); 2212 static_assert(static_cast<uint32_t>(InputContext::Origin::ORIGIN_MAIN) == 2213 INPUT_CONTEXT_ORIGIN_MAIN); 2214 static_assert(static_cast<uint32_t>(InputContext::Origin::ORIGIN_CONTENT) == 2215 INPUT_CONTEXT_ORIGIN_CONTENT); 2216 MOZ_ASSERT(context.mOrigin == InputContext::Origin::ORIGIN_MAIN || 2217 context.mOrigin == InputContext::Origin::ORIGIN_CONTENT); 2218 *aOrigin = static_cast<uint32_t>(context.mOrigin); 2219 return NS_OK; 2220 } 2221 2222 NS_IMETHODIMP 2223 nsDOMWindowUtils::GetNodeObservedByIMEContentObserver(nsINode** aNode) { 2224 NS_ENSURE_ARG_POINTER(aNode); 2225 2226 IMEContentObserver* observer = IMEStateManager::GetActiveContentObserver(); 2227 if (!observer) { 2228 *aNode = nullptr; 2229 return NS_OK; 2230 } 2231 *aNode = do_AddRef(observer->GetObservingElement()).take(); 2232 return NS_OK; 2233 } 2234 2235 NS_IMETHODIMP 2236 nsDOMWindowUtils::GetCanvasBackgroundColor(nsAString& aColor) { 2237 if (RefPtr<Document> doc = GetDocument()) { 2238 doc->FlushPendingNotifications(FlushType::Frames); 2239 } 2240 nscolor color = NS_RGB(255, 255, 255); 2241 if (PresShell* presShell = GetPresShell()) { 2242 color = presShell->ComputeCanvasBackground().mViewport.mColor; 2243 } 2244 nsStyleUtil::GetSerializedColorValue(color, aColor); 2245 return NS_OK; 2246 } 2247 2248 NS_IMETHODIMP 2249 nsDOMWindowUtils::GetFocusedInputType(nsAString& aType) { 2250 nsCOMPtr<nsIWidget> widget = GetWidget(); 2251 if (!widget) { 2252 return NS_ERROR_FAILURE; 2253 } 2254 2255 aType = widget->GetInputContext().mHTMLInputType; 2256 return NS_OK; 2257 } 2258 2259 NS_IMETHODIMP 2260 nsDOMWindowUtils::GetFocusedActionHint(nsAString& aType) { 2261 nsCOMPtr<nsIWidget> widget = GetWidget(); 2262 if (!widget) { 2263 return NS_ERROR_FAILURE; 2264 } 2265 2266 aType = widget->GetInputContext().mActionHint; 2267 return NS_OK; 2268 } 2269 2270 NS_IMETHODIMP 2271 nsDOMWindowUtils::GetFocusedInputMode(nsAString& aInputMode) { 2272 nsCOMPtr<nsIWidget> widget = GetWidget(); 2273 if (!widget) { 2274 return NS_ERROR_FAILURE; 2275 } 2276 aInputMode = widget->GetInputContext().mHTMLInputMode; 2277 return NS_OK; 2278 } 2279 2280 NS_IMETHODIMP 2281 nsDOMWindowUtils::GetFocusedAutocapitalize(nsAString& aAutocapitalize) { 2282 nsCOMPtr<nsIWidget> widget = GetWidget(); 2283 if (!widget) { 2284 return NS_ERROR_FAILURE; 2285 } 2286 aAutocapitalize = widget->GetInputContext().mAutocapitalize; 2287 return NS_OK; 2288 } 2289 2290 NS_IMETHODIMP 2291 nsDOMWindowUtils::GetFocusedAutocorrect(bool* aAutocorrect) { 2292 nsCOMPtr<nsIWidget> widget = GetWidget(); 2293 if (!widget) { 2294 return NS_ERROR_FAILURE; 2295 } 2296 *aAutocorrect = widget->GetInputContext().mAutocorrect; 2297 return NS_OK; 2298 } 2299 2300 NS_IMETHODIMP 2301 nsDOMWindowUtils::GetViewId(Element* aElement, nsViewID* aResult) { 2302 if (aElement && nsLayoutUtils::FindIDFor(aElement, aResult)) { 2303 return NS_OK; 2304 } 2305 return NS_ERROR_NOT_AVAILABLE; 2306 } 2307 2308 NS_IMETHODIMP nsDOMWindowUtils::DispatchDOMEventViaPresShellForTesting( 2309 nsINode* aTarget, Event* aEvent, bool* aRetVal) { 2310 NS_ENSURE_STATE(aEvent); 2311 aEvent->SetTrusted(true); 2312 WidgetEvent* internalEvent = aEvent->WidgetEventPtr(); 2313 NS_ENSURE_STATE(internalEvent); 2314 // This API is currently used only by EventUtils.js. Thus we should always 2315 // set mIsSynthesizedForTests to true. 2316 internalEvent->mFlags.mIsSynthesizedForTests = true; 2317 nsCOMPtr<nsIContent> content = nsIContent::FromNodeOrNull(aTarget); 2318 NS_ENSURE_STATE(content); 2319 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 2320 if (content->OwnerDoc()->GetWindow() != window) { 2321 return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; 2322 } 2323 nsCOMPtr<Document> targetDoc = content->GetUncomposedDoc(); 2324 NS_ENSURE_STATE(targetDoc); 2325 RefPtr<PresShell> targetPresShell = targetDoc->GetPresShell(); 2326 NS_ENSURE_STATE(targetPresShell); 2327 2328 WidgetGUIEvent* guiEvent = internalEvent->AsGUIEvent(); 2329 if (guiEvent && !guiEvent->mWidget) { 2330 auto* pc = GetPresContext(); 2331 auto* widget = pc ? pc->GetRootWidget() : nullptr; 2332 // In content, screen coordinates would have been 2333 // transformed by BrowserParent::TransformParentToChild 2334 // so we do that here. 2335 if (widget) { 2336 guiEvent->mWidget = widget; 2337 2338 // Setting the widget makes the event's mRefPoint coordinates 2339 // widget-relative, so we transform them from being 2340 // screen-relative here. 2341 guiEvent->mRefPoint -= widget->WidgetToScreenOffset(); 2342 } 2343 } 2344 2345 targetDoc->FlushPendingNotifications(FlushType::Layout); 2346 2347 nsEventStatus status = nsEventStatus_eIgnore; 2348 targetPresShell->HandleEventWithTarget(internalEvent, nullptr, content, 2349 &status); 2350 *aRetVal = (status != nsEventStatus_eConsumeNoDefault); 2351 return NS_OK; 2352 } 2353 2354 static void InitEvent(WidgetGUIEvent& aEvent, 2355 LayoutDeviceIntPoint* aPt = nullptr) { 2356 if (aPt) { 2357 aEvent.mRefPoint = *aPt; 2358 } 2359 } 2360 2361 NS_IMETHODIMP 2362 nsDOMWindowUtils::SendQueryContentEvent(uint32_t aType, int64_t aOffset, 2363 uint32_t aLength, int32_t aX, 2364 int32_t aY, uint32_t aAdditionalFlags, 2365 nsIQueryContentEventResult** aResult) { 2366 *aResult = nullptr; 2367 2368 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 2369 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 2370 2371 nsIDocShell* docShell = window->GetDocShell(); 2372 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 2373 2374 PresShell* presShell = docShell->GetPresShell(); 2375 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); 2376 2377 nsPresContext* presContext = presShell->GetPresContext(); 2378 NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); 2379 2380 // get the widget to send the event to 2381 nsCOMPtr<nsIWidget> widget = GetWidget(); 2382 if (!widget) { 2383 return NS_ERROR_FAILURE; 2384 } 2385 2386 EventMessage message; 2387 switch (aType) { 2388 case QUERY_SELECTED_TEXT: 2389 message = eQuerySelectedText; 2390 break; 2391 case QUERY_TEXT_CONTENT: 2392 message = eQueryTextContent; 2393 break; 2394 case QUERY_CARET_RECT: 2395 message = eQueryCaretRect; 2396 break; 2397 case QUERY_TEXT_RECT: 2398 message = eQueryTextRect; 2399 break; 2400 case QUERY_EDITOR_RECT: 2401 message = eQueryEditorRect; 2402 break; 2403 case QUERY_CHARACTER_AT_POINT: 2404 message = eQueryCharacterAtPoint; 2405 break; 2406 case QUERY_TEXT_RECT_ARRAY: 2407 message = eQueryTextRectArray; 2408 break; 2409 default: 2410 return NS_ERROR_INVALID_ARG; 2411 } 2412 2413 SelectionType selectionType = SelectionType::eNormal; 2414 static const uint32_t kSelectionFlags = 2415 QUERY_CONTENT_FLAG_SELECTION_SPELLCHECK | 2416 QUERY_CONTENT_FLAG_SELECTION_IME_RAWINPUT | 2417 QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDRAWTEXT | 2418 QUERY_CONTENT_FLAG_SELECTION_IME_CONVERTEDTEXT | 2419 QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDCONVERTEDTEXT | 2420 QUERY_CONTENT_FLAG_SELECTION_ACCESSIBILITY | 2421 QUERY_CONTENT_FLAG_SELECTION_FIND | 2422 QUERY_CONTENT_FLAG_SELECTION_URLSECONDARY | 2423 QUERY_CONTENT_FLAG_SELECTION_URLSTRIKEOUT; 2424 switch (aAdditionalFlags & kSelectionFlags) { 2425 case QUERY_CONTENT_FLAG_SELECTION_SPELLCHECK: 2426 selectionType = SelectionType::eSpellCheck; 2427 break; 2428 case QUERY_CONTENT_FLAG_SELECTION_IME_RAWINPUT: 2429 selectionType = SelectionType::eIMERawClause; 2430 break; 2431 case QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDRAWTEXT: 2432 selectionType = SelectionType::eIMESelectedRawClause; 2433 break; 2434 case QUERY_CONTENT_FLAG_SELECTION_IME_CONVERTEDTEXT: 2435 selectionType = SelectionType::eIMEConvertedClause; 2436 break; 2437 case QUERY_CONTENT_FLAG_SELECTION_IME_SELECTEDCONVERTEDTEXT: 2438 selectionType = SelectionType::eIMESelectedClause; 2439 break; 2440 case QUERY_CONTENT_FLAG_SELECTION_ACCESSIBILITY: 2441 selectionType = SelectionType::eAccessibility; 2442 break; 2443 case QUERY_CONTENT_FLAG_SELECTION_FIND: 2444 selectionType = SelectionType::eFind; 2445 break; 2446 case QUERY_CONTENT_FLAG_SELECTION_URLSECONDARY: 2447 selectionType = SelectionType::eURLSecondary; 2448 break; 2449 case QUERY_CONTENT_FLAG_SELECTION_URLSTRIKEOUT: 2450 selectionType = SelectionType::eURLStrikeout; 2451 break; 2452 case 0: 2453 break; 2454 default: 2455 return NS_ERROR_INVALID_ARG; 2456 } 2457 2458 if (selectionType != SelectionType::eNormal && 2459 message != eQuerySelectedText) { 2460 return NS_ERROR_INVALID_ARG; 2461 } 2462 2463 nsCOMPtr<nsIWidget> targetWidget = widget; 2464 LayoutDeviceIntPoint pt(aX, aY); 2465 2466 WidgetQueryContentEvent::Options options; 2467 options.mUseNativeLineBreak = 2468 !(aAdditionalFlags & QUERY_CONTENT_FLAG_USE_XP_LINE_BREAK); 2469 options.mRelativeToInsertionPoint = 2470 (aAdditionalFlags & 2471 QUERY_CONTENT_FLAG_OFFSET_RELATIVE_TO_INSERTION_POINT) != 0; 2472 if (options.mRelativeToInsertionPoint) { 2473 switch (message) { 2474 case eQueryTextContent: 2475 case eQueryCaretRect: 2476 case eQueryTextRect: 2477 break; 2478 default: 2479 return NS_ERROR_INVALID_ARG; 2480 } 2481 } else if (aOffset < 0) { 2482 return NS_ERROR_INVALID_ARG; 2483 } 2484 2485 if (message == eQueryCharacterAtPoint) { 2486 // Looking for the widget at the point. 2487 nsIFrame* popupFrame = nsLayoutUtils::GetPopupFrameForPoint( 2488 presContext->GetRootPresContext(), widget, pt); 2489 2490 LayoutDeviceIntRect widgetBounds = widget->GetClientBounds(); 2491 widgetBounds.MoveTo(0, 0); 2492 2493 // There is no popup frame at the point and the point isn't in our widget, 2494 // we cannot process this request. 2495 NS_ENSURE_TRUE(popupFrame || widgetBounds.Contains(pt), NS_ERROR_FAILURE); 2496 2497 // Fire the event on the widget at the point 2498 if (popupFrame) { 2499 targetWidget = popupFrame->GetNearestWidget(); 2500 } 2501 } 2502 2503 pt += widget->WidgetToScreenOffset() - targetWidget->WidgetToScreenOffset(); 2504 2505 WidgetQueryContentEvent queryEvent(true, message, targetWidget); 2506 InitEvent(queryEvent, &pt); 2507 2508 switch (message) { 2509 case eQueryTextContent: 2510 queryEvent.InitForQueryTextContent(aOffset, aLength, options); 2511 break; 2512 case eQueryCaretRect: 2513 queryEvent.InitForQueryCaretRect(aOffset, options); 2514 break; 2515 case eQueryTextRect: 2516 queryEvent.InitForQueryTextRect(aOffset, aLength, options); 2517 break; 2518 case eQuerySelectedText: 2519 queryEvent.InitForQuerySelectedText(selectionType, options); 2520 break; 2521 case eQueryTextRectArray: 2522 queryEvent.InitForQueryTextRectArray(aOffset, aLength, options); 2523 break; 2524 default: 2525 queryEvent.Init(options); 2526 break; 2527 } 2528 2529 targetWidget->DispatchEvent(&queryEvent); 2530 2531 auto* result = new nsQueryContentEventResult(std::move(queryEvent)); 2532 result->SetEventResult(widget); 2533 NS_ADDREF(*aResult = result); 2534 return NS_OK; 2535 } 2536 2537 NS_IMETHODIMP 2538 nsDOMWindowUtils::SendSelectionSetEvent(uint32_t aOffset, uint32_t aLength, 2539 uint32_t aAdditionalFlags, 2540 bool* aResult) { 2541 *aResult = false; 2542 2543 // get the widget to send the event to 2544 nsCOMPtr<nsIWidget> widget = GetWidget(); 2545 if (!widget) { 2546 return NS_ERROR_FAILURE; 2547 } 2548 2549 WidgetSelectionEvent selectionEvent(true, eSetSelection, widget); 2550 InitEvent(selectionEvent); 2551 2552 selectionEvent.mOffset = aOffset; 2553 selectionEvent.mLength = aLength; 2554 selectionEvent.mReversed = (aAdditionalFlags & SELECTION_SET_FLAG_REVERSE); 2555 selectionEvent.mUseNativeLineBreak = 2556 !(aAdditionalFlags & SELECTION_SET_FLAG_USE_XP_LINE_BREAK); 2557 2558 widget->DispatchEvent(&selectionEvent); 2559 2560 *aResult = selectionEvent.mSucceeded; 2561 return NS_OK; 2562 } 2563 2564 NS_IMETHODIMP 2565 nsDOMWindowUtils::SendContentCommandEvent(const nsAString& aType, 2566 nsITransferable* aTransferable, 2567 const nsAString& aString, 2568 uint32_t aOffset, 2569 const nsAString& aReplaceSrcString, 2570 uint32_t aAdditionalFlags) { 2571 // get the widget to send the event to 2572 nsCOMPtr<nsIWidget> widget = GetWidget(); 2573 if (!widget) return NS_ERROR_FAILURE; 2574 2575 EventMessage msg; 2576 if (aType.EqualsLiteral("cut")) { 2577 msg = eContentCommandCut; 2578 } else if (aType.EqualsLiteral("copy")) { 2579 msg = eContentCommandCopy; 2580 } else if (aType.EqualsLiteral("paste")) { 2581 msg = eContentCommandPaste; 2582 } else if (aType.EqualsLiteral("delete")) { 2583 msg = eContentCommandDelete; 2584 } else if (aType.EqualsLiteral("undo")) { 2585 msg = eContentCommandUndo; 2586 } else if (aType.EqualsLiteral("redo")) { 2587 msg = eContentCommandRedo; 2588 } else if (aType.EqualsLiteral("insertText")) { 2589 msg = eContentCommandInsertText; 2590 } else if (aType.EqualsLiteral("replaceText")) { 2591 msg = eContentCommandReplaceText; 2592 } else if (aType.EqualsLiteral("pasteTransferable")) { 2593 msg = eContentCommandPasteTransferable; 2594 } else { 2595 return NS_ERROR_FAILURE; 2596 } 2597 2598 WidgetContentCommandEvent event(true, msg, widget); 2599 if (msg == eContentCommandInsertText) { 2600 event.mString.emplace(aString); 2601 } else if (msg == eContentCommandReplaceText) { 2602 event.mString.emplace(aString); 2603 event.mSelection.mReplaceSrcString = aReplaceSrcString; 2604 event.mSelection.mOffset = aOffset; 2605 event.mSelection.mPreventSetSelection = 2606 !!(aAdditionalFlags & CONTENT_COMMAND_FLAG_PREVENT_SET_SELECTION); 2607 } else if (msg == eContentCommandPasteTransferable) { 2608 event.mTransferable = aTransferable; 2609 } 2610 2611 widget->DispatchEvent(&event); 2612 return NS_OK; 2613 } 2614 2615 NS_IMETHODIMP 2616 nsDOMWindowUtils::GetClassName(JS::Handle<JS::Value> aObject, JSContext* aCx, 2617 char** aName) { 2618 // Our argument must be a non-null object. 2619 if (aObject.isPrimitive()) { 2620 return NS_ERROR_XPC_BAD_CONVERT_JS; 2621 } 2622 2623 *aName = NS_xstrdup(JS::GetClass(aObject.toObjectOrNull())->name); 2624 return NS_OK; 2625 } 2626 2627 NS_IMETHODIMP 2628 nsDOMWindowUtils::GetVisitedDependentComputedStyle( 2629 Element* aElement, const nsAString& aPseudoElement, 2630 const nsAString& aPropertyName, nsAString& aResult) { 2631 aResult.Truncate(); 2632 2633 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 2634 NS_ENSURE_STATE(window && aElement); 2635 nsCOMPtr<nsPIDOMWindowInner> innerWindow = window->GetCurrentInnerWindow(); 2636 NS_ENSURE_STATE(innerWindow); 2637 2638 nsCOMPtr<nsICSSDeclaration> decl; 2639 { 2640 ErrorResult rv; 2641 decl = innerWindow->GetComputedStyle(*aElement, aPseudoElement, rv); 2642 RETURN_NSRESULT_ON_FAILURE(rv); 2643 } 2644 2645 nsAutoCString result; 2646 2647 static_cast<nsComputedDOMStyle*>(decl.get())->SetExposeVisitedStyle(true); 2648 decl->GetPropertyValue(NS_ConvertUTF16toUTF8(aPropertyName), result); 2649 static_cast<nsComputedDOMStyle*>(decl.get())->SetExposeVisitedStyle(false); 2650 2651 CopyUTF8toUTF16(result, aResult); 2652 return NS_OK; 2653 } 2654 2655 NS_IMETHODIMP 2656 nsDOMWindowUtils::EnterModalState() { 2657 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 2658 NS_ENSURE_STATE(window); 2659 2660 window->EnterModalState(); 2661 return NS_OK; 2662 } 2663 2664 NS_IMETHODIMP 2665 nsDOMWindowUtils::LeaveModalState() { 2666 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 2667 NS_ENSURE_STATE(window); 2668 2669 window->LeaveModalState(); 2670 return NS_OK; 2671 } 2672 2673 NS_IMETHODIMP 2674 nsDOMWindowUtils::IsInModalState(bool* retval) { 2675 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 2676 NS_ENSURE_STATE(window); 2677 2678 *retval = nsGlobalWindowOuter::Cast(window)->IsInModalState(); 2679 return NS_OK; 2680 } 2681 2682 NS_IMETHODIMP 2683 nsDOMWindowUtils::SuspendTimeouts() { 2684 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 2685 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 2686 2687 nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow(); 2688 NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE); 2689 2690 inner->Suspend(); 2691 2692 return NS_OK; 2693 } 2694 2695 NS_IMETHODIMP 2696 nsDOMWindowUtils::ResumeTimeouts() { 2697 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 2698 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 2699 2700 nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow(); 2701 NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE); 2702 2703 inner->Resume(); 2704 2705 return NS_OK; 2706 } 2707 2708 NS_IMETHODIMP 2709 nsDOMWindowUtils::GetLayerManagerType(nsAString& aType) { 2710 nsCOMPtr<nsIWidget> widget = GetWidget(); 2711 if (!widget) return NS_ERROR_FAILURE; 2712 2713 WindowRenderer* renderer = widget->GetWindowRenderer(); 2714 if (!renderer) return NS_ERROR_FAILURE; 2715 2716 renderer->GetBackendName(aType); 2717 2718 return NS_OK; 2719 } 2720 2721 NS_IMETHODIMP 2722 nsDOMWindowUtils::GetLayerManagerRemote(bool* retval) { 2723 nsCOMPtr<nsIWidget> widget = GetWidget(); 2724 if (!widget) return NS_ERROR_FAILURE; 2725 2726 WindowRenderer* renderer = widget->GetWindowRenderer(); 2727 if (!renderer) return NS_ERROR_FAILURE; 2728 2729 *retval = !!renderer->AsKnowsCompositor(); 2730 return NS_OK; 2731 } 2732 2733 NS_IMETHODIMP 2734 nsDOMWindowUtils::GetIsWebRenderRequested(bool* retval) { 2735 *retval = gfxPlatform::WebRenderPrefEnabled() || 2736 gfxPlatform::WebRenderEnvvarEnabled(); 2737 return NS_OK; 2738 } 2739 2740 NS_IMETHODIMP 2741 nsDOMWindowUtils::GetCurrentAudioBackend(nsAString& aBackend) { 2742 CubebUtils::GetCurrentBackend(aBackend); 2743 return NS_OK; 2744 } 2745 2746 NS_IMETHODIMP 2747 nsDOMWindowUtils::GetCurrentMaxAudioChannels(uint32_t* aChannels) { 2748 *aChannels = CubebUtils::MaxNumberOfChannels(); 2749 return NS_OK; 2750 } 2751 2752 NS_IMETHODIMP 2753 nsDOMWindowUtils::GetCurrentPreferredSampleRate(uint32_t* aRate) { 2754 nsCOMPtr<Document> doc = GetDocument(); 2755 *aRate = CubebUtils::PreferredSampleRate( 2756 doc ? doc->ShouldResistFingerprinting(RFPTarget::AudioSampleRate) 2757 : nsContentUtils::ShouldResistFingerprinting( 2758 "Fallback", RFPTarget::AudioSampleRate)); 2759 return NS_OK; 2760 } 2761 2762 NS_IMETHODIMP 2763 nsDOMWindowUtils::DefaultDevicesRoundTripLatency(Promise** aOutPromise) { 2764 NS_ENSURE_ARG_POINTER(aOutPromise); 2765 *aOutPromise = nullptr; 2766 2767 nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow); 2768 NS_ENSURE_STATE(outer); 2769 nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow(); 2770 NS_ENSURE_STATE(inner); 2771 2772 ErrorResult err; 2773 RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err); 2774 if (NS_WARN_IF(err.Failed())) { 2775 return err.StealNSResult(); 2776 } 2777 2778 NS_ADDREF(promise.get()); 2779 void* p = reinterpret_cast<void*>(promise.get()); 2780 NS_DispatchBackgroundTask( 2781 NS_NewRunnableFunction("DefaultDevicesRoundTripLatency", [p]() { 2782 double mean, stddev; 2783 bool success = 2784 CubebUtils::EstimatedLatencyDefaultDevices(&mean, &stddev); 2785 2786 NS_DispatchToMainThread(NS_NewRunnableFunction( 2787 "DefaultDevicesRoundTripLatency", [p, success, mean, stddev]() { 2788 Promise* promise = reinterpret_cast<Promise*>(p); 2789 if (!success) { 2790 promise->MaybeReject(NS_ERROR_FAILURE); 2791 NS_RELEASE(promise); 2792 return; 2793 } 2794 nsTArray<double> a; 2795 a.AppendElement(mean); 2796 a.AppendElement(stddev); 2797 promise->MaybeResolve(a); 2798 NS_RELEASE(promise); 2799 })); 2800 })); 2801 2802 promise.forget(aOutPromise); 2803 return NS_OK; 2804 } 2805 2806 NS_IMETHODIMP 2807 nsDOMWindowUtils::AudioDevices(uint16_t aSide, nsIArray** aDevices) { 2808 NS_ENSURE_ARG_POINTER(aDevices); 2809 NS_ENSURE_ARG((aSide == AUDIO_INPUT) || (aSide == AUDIO_OUTPUT)); 2810 *aDevices = nullptr; 2811 2812 nsresult rv = NS_OK; 2813 nsCOMPtr<nsIMutableArray> devices = 2814 do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); 2815 NS_ENSURE_SUCCESS(rv, rv); 2816 2817 RefPtr<CubebDeviceEnumerator> enumerator = Enumerator::GetInstance(); 2818 RefPtr<const CubebDeviceEnumerator::AudioDeviceSet> collection; 2819 if (aSide == AUDIO_INPUT) { 2820 collection = enumerator->EnumerateAudioInputDevices(); 2821 } else { 2822 collection = enumerator->EnumerateAudioOutputDevices(); 2823 } 2824 2825 for (const auto& device : *collection) { 2826 devices->AppendElement(device); 2827 } 2828 2829 devices.forget(aDevices); 2830 2831 return NS_OK; 2832 } 2833 2834 NS_IMETHODIMP 2835 nsDOMWindowUtils::StartFrameTimeRecording(uint32_t* startIndex) { 2836 NS_ENSURE_ARG_POINTER(startIndex); 2837 2838 nsCOMPtr<nsIWidget> widget = GetWidget(); 2839 if (!widget) return NS_ERROR_FAILURE; 2840 2841 WindowRenderer* renderer = widget->GetWindowRenderer(); 2842 if (!renderer) return NS_ERROR_FAILURE; 2843 2844 const uint32_t kRecordingMinSize = 60 * 10; // 10 seconds @60 fps. 2845 const uint32_t kRecordingMaxSize = 60 * 60 * 60; // One hour 2846 uint32_t bufferSize = 2847 Preferences::GetUint("toolkit.framesRecording.bufferSize", uint32_t(0)); 2848 bufferSize = std::min(bufferSize, kRecordingMaxSize); 2849 bufferSize = std::max(bufferSize, kRecordingMinSize); 2850 *startIndex = renderer->StartFrameTimeRecording(bufferSize); 2851 2852 return NS_OK; 2853 } 2854 2855 NS_IMETHODIMP 2856 nsDOMWindowUtils::StopFrameTimeRecording(uint32_t startIndex, 2857 nsTArray<float>& frameIntervals) { 2858 nsCOMPtr<nsIWidget> widget = GetWidget(); 2859 if (!widget) return NS_ERROR_FAILURE; 2860 2861 WindowRenderer* renderer = widget->GetWindowRenderer(); 2862 if (!renderer) return NS_ERROR_FAILURE; 2863 2864 renderer->StopFrameTimeRecording(startIndex, frameIntervals); 2865 2866 return NS_OK; 2867 } 2868 2869 NS_IMETHODIMP 2870 nsDOMWindowUtils::AdvanceTimeAndRefresh(int64_t aMilliseconds) { 2871 // Before we advance the time, we should trigger any animations that are 2872 // waiting to start. This is because there are many tests that call this 2873 // which expect animations to start immediately. Ideally, we should make 2874 // all these tests do an asynchronous wait on the corresponding animation's 2875 // 'ready' promise before continuing. Then we could remove the special 2876 // handling here and the code path followed when testing would more closely 2877 // match the code path during regular operation. Filed as bug 1112957. 2878 nsPresContext* presContext = GetPresContext(); 2879 if (presContext) { 2880 presContext->Document()->Timeline()->TriggerAllPendingAnimationsNow(); 2881 2882 RefPtr<nsRefreshDriver> driver = presContext->RefreshDriver(); 2883 driver->AdvanceTimeAndRefresh(aMilliseconds); 2884 2885 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) { 2886 wrbc->SendSetTestSampleTime(driver->MostRecentRefresh()); 2887 } 2888 } 2889 2890 return NS_OK; 2891 } 2892 2893 NS_IMETHODIMP 2894 nsDOMWindowUtils::GetLastTransactionId(uint64_t* aLastTransactionId) { 2895 nsCOMPtr<nsIDocShell> docShell = GetDocShell(); 2896 if (!docShell) { 2897 return NS_ERROR_UNEXPECTED; 2898 } 2899 2900 nsCOMPtr<nsIDocShellTreeItem> rootTreeItem; 2901 docShell->GetInProcessRootTreeItem(getter_AddRefs(rootTreeItem)); 2902 docShell = do_QueryInterface(rootTreeItem); 2903 if (!docShell) { 2904 return NS_ERROR_UNEXPECTED; 2905 } 2906 2907 nsPresContext* presContext = docShell->GetPresContext(); 2908 if (!presContext) { 2909 return NS_ERROR_UNEXPECTED; 2910 } 2911 2912 nsRefreshDriver* driver = presContext->RefreshDriver(); 2913 *aLastTransactionId = uint64_t(driver->LastTransactionId()); 2914 return NS_OK; 2915 } 2916 2917 NS_IMETHODIMP 2918 nsDOMWindowUtils::RestoreNormalRefresh() { 2919 // Kick the compositor out of test mode before the refresh driver, so that 2920 // the refresh driver doesn't send an update that gets ignored by the 2921 // compositor. 2922 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) { 2923 wrbc->SendLeaveTestMode(); 2924 } 2925 2926 if (nsPresContext* pc = GetPresContext()) { 2927 nsRefreshDriver* driver = pc->RefreshDriver(); 2928 driver->RestoreNormalRefresh(); 2929 } 2930 2931 return NS_OK; 2932 } 2933 2934 NS_IMETHODIMP 2935 nsDOMWindowUtils::GetIsTestControllingRefreshes(bool* aResult) { 2936 nsPresContext* pc = GetPresContext(); 2937 *aResult = 2938 pc ? pc->RefreshDriver()->IsTestControllingRefreshesEnabled() : false; 2939 2940 return NS_OK; 2941 } 2942 2943 NS_IMETHODIMP 2944 nsDOMWindowUtils::GetAsyncPanZoomEnabled(bool* aResult) { 2945 nsIWidget* widget = GetWidget(); 2946 if (widget) { 2947 *aResult = widget->AsyncPanZoomEnabled(); 2948 } else { 2949 *aResult = gfxPlatform::AsyncPanZoomEnabled(); 2950 } 2951 return NS_OK; 2952 } 2953 2954 NS_IMETHODIMP 2955 nsDOMWindowUtils::SetAsyncScrollOffset(Element* aElement, float aX, float aY) { 2956 if (!aElement) { 2957 return NS_ERROR_INVALID_ARG; 2958 } 2959 ScrollableLayerGuid::ViewID viewId; 2960 if (!nsLayoutUtils::FindIDFor(aElement, &viewId)) { 2961 return NS_ERROR_UNEXPECTED; 2962 } 2963 nsIWidget* widget = GetWidget(); 2964 if (!widget) { 2965 return NS_ERROR_FAILURE; 2966 } 2967 WindowRenderer* renderer = widget->GetWindowRenderer(); 2968 if (!renderer) { 2969 return NS_ERROR_FAILURE; 2970 } 2971 if (WebRenderLayerManager* wr = renderer->AsWebRender()) { 2972 WebRenderBridgeChild* wrbc = wr->WrBridge(); 2973 if (!wrbc) { 2974 return NS_ERROR_UNEXPECTED; 2975 } 2976 wrbc->SendSetAsyncScrollOffset(viewId, aX, aY); 2977 return NS_OK; 2978 } 2979 return NS_ERROR_UNEXPECTED; 2980 } 2981 2982 NS_IMETHODIMP 2983 nsDOMWindowUtils::SetAsyncZoom(Element* aRootElement, float aValue) { 2984 if (!aRootElement) { 2985 return NS_ERROR_INVALID_ARG; 2986 } 2987 ScrollableLayerGuid::ViewID viewId; 2988 if (!nsLayoutUtils::FindIDFor(aRootElement, &viewId)) { 2989 return NS_ERROR_UNEXPECTED; 2990 } 2991 nsIWidget* widget = GetWidget(); 2992 if (!widget) { 2993 return NS_ERROR_FAILURE; 2994 } 2995 WindowRenderer* renderer = widget->GetWindowRenderer(); 2996 if (!renderer) { 2997 return NS_ERROR_FAILURE; 2998 } 2999 if (WebRenderLayerManager* wr = renderer->AsWebRender()) { 3000 WebRenderBridgeChild* wrbc = wr->WrBridge(); 3001 if (!wrbc) { 3002 return NS_ERROR_UNEXPECTED; 3003 } 3004 wrbc->SendSetAsyncZoom(viewId, aValue); 3005 return NS_OK; 3006 } 3007 return NS_ERROR_UNEXPECTED; 3008 } 3009 3010 NS_IMETHODIMP 3011 nsDOMWindowUtils::FlushApzRepaints(Element* aElement, bool* aOutResult) { 3012 nsIWidget* widget = GetWidgetForElement(aElement); 3013 if (!widget) { 3014 *aOutResult = false; 3015 return NS_OK; 3016 } 3017 // If APZ is not enabled, this function is a no-op. 3018 if (!widget->AsyncPanZoomEnabled()) { 3019 *aOutResult = false; 3020 return NS_OK; 3021 } 3022 WindowRenderer* renderer = widget->GetWindowRenderer(); 3023 if (!renderer) { 3024 *aOutResult = false; 3025 return NS_OK; 3026 } 3027 if (WebRenderLayerManager* wr = renderer->AsWebRender()) { 3028 WebRenderBridgeChild* wrbc = wr->WrBridge(); 3029 if (!wrbc) { 3030 return NS_ERROR_UNEXPECTED; 3031 } 3032 wrbc->SendFlushApzRepaints(); 3033 *aOutResult = true; 3034 return NS_OK; 3035 } 3036 *aOutResult = false; 3037 return NS_OK; 3038 } 3039 3040 NS_IMETHODIMP 3041 nsDOMWindowUtils::DisableApzForElement(Element* aElement) { 3042 aElement->SetProperty(nsGkAtoms::apzDisabled, reinterpret_cast<void*>(true)); 3043 if (ScrollContainerFrame* sf = 3044 nsLayoutUtils::FindScrollContainerFrameFor(aElement)) { 3045 sf->SchedulePaint(); 3046 } 3047 return NS_OK; 3048 } 3049 3050 NS_IMETHODIMP 3051 nsDOMWindowUtils::IsApzDisabledForElement(Element* aElement, bool* aOutResult) { 3052 *aOutResult = nsLayoutUtils::ShouldDisableApzForElement(aElement); 3053 return NS_OK; 3054 } 3055 3056 static nsTArray<ScrollContainerFrame*> CollectScrollableAncestors( 3057 nsIFrame* aStart) { 3058 nsTArray<ScrollContainerFrame*> result; 3059 nsIFrame* frame = aStart; 3060 while (frame) { 3061 frame = DisplayPortUtils::OneStepInAsyncScrollableAncestorChain(frame); 3062 if (!frame) { 3063 break; 3064 } 3065 ScrollContainerFrame* scrollAncestor = 3066 nsLayoutUtils::GetAsyncScrollableAncestorFrame(frame); 3067 if (!scrollAncestor) { 3068 break; 3069 } 3070 result.AppendElement(scrollAncestor); 3071 frame = do_QueryFrame(scrollAncestor); 3072 } 3073 return result; 3074 } 3075 3076 struct CaretInfo { 3077 /* the text content including the caret */ 3078 nsIContent* textContent; 3079 /* the text frame bounds relative to the root scroll contaner frame */ 3080 CSSRect textFrameBoundsRelativeToRootScroller; 3081 /* the caret rect relative to the text frame */ 3082 Maybe<nsRect> caretRectRelativeToTextFrame; 3083 /* the primary frame or the text frame for the caret */ 3084 nsIFrame* frame; 3085 }; 3086 3087 static CaretInfo GetCaretContentAndBounds( 3088 const ScrollContainerFrame* aRootScrollContainerFrame, Element* aElement) { 3089 nsIContent* content = aElement; 3090 CSSRect bounds; 3091 3092 if (!aRootScrollContainerFrame) { 3093 return CaretInfo{content, bounds, Nothing(), content->GetPrimaryFrame()}; 3094 } 3095 3096 Maybe<nsRect> caretRect; 3097 // When focused elment is content editable or <textarea> element, 3098 // focused element will have multi-line content. 3099 nsIFrame* frame = aElement->GetPrimaryFrame(); 3100 if (frame) { 3101 RefPtr<nsCaret> caret = frame->PresShell()->GetCaret(); 3102 if (caret && caret->IsVisible()) { 3103 nsRect rect; 3104 if (nsIFrame* textFrame = caret->GetGeometry(&rect)) { 3105 // This |textFrame| is a text frame and the returned rectangle 3106 // represents the caret position relative to the text frame, so we need 3107 // to pass the rectangle to ScrollFrameIntoView along with the text 3108 // frame. 3109 bounds = nsLayoutUtils::GetBoundingFrameRect(frame, 3110 aRootScrollContainerFrame); 3111 content = frame->GetContent(); 3112 caretRect = Some(rect); 3113 frame = textFrame; 3114 } 3115 } 3116 } 3117 if (bounds.IsEmpty()) { 3118 // Fallback if no caret frame. 3119 bounds = nsLayoutUtils::GetBoundingContentRect(aElement, 3120 aRootScrollContainerFrame); 3121 } 3122 3123 return CaretInfo{content, bounds, caretRect, frame}; 3124 } 3125 3126 NS_IMETHODIMP 3127 nsDOMWindowUtils::ZoomToFocusedInput() { 3128 if (!Preferences::GetBool("apz.zoom-to-focused-input.enabled")) { 3129 APZZTFI_LOG("disabled by pref"); 3130 return NS_OK; 3131 } 3132 3133 nsIWidget* widget = GetWidget(); 3134 if (!widget) { 3135 return NS_OK; 3136 } 3137 3138 // If APZ is not enabled, this function is a no-op. 3139 // 3140 // FIXME(emilio): This is not quite true anymore now that we also 3141 // ScrollIntoView() too... 3142 if (!widget->AsyncPanZoomEnabled()) { 3143 return NS_OK; 3144 } 3145 3146 const RefPtr<Element> element = nsFocusManager::GetFocusedElementStatic(); 3147 if (!element) { 3148 APZZTFI_LOG("no focused element"); 3149 return NS_OK; 3150 } 3151 3152 RefPtr<PresShell> presShell = 3153 APZCCallbackHelper::GetRootContentDocumentPresShellForContent(element); 3154 if (!presShell) { 3155 return NS_OK; 3156 } 3157 3158 ScrollContainerFrame* rootScrollContainerFrame = 3159 presShell->GetRootScrollContainerFrame(); 3160 auto caretInfo = GetCaretContentAndBounds(rootScrollContainerFrame, element); 3161 APZZTFI_LOG("calculated rect %s (caret rect %s)", 3162 ToString(caretInfo.textFrameBoundsRelativeToRootScroller).c_str(), 3163 ToString(caretInfo.caretRectRelativeToTextFrame).c_str()); 3164 3165 // The content may be inside a scrollable subframe inside a non-scrollable 3166 // root content document. In this scenario, we want to ensure that the 3167 // main-thread side knows to scroll the content into view before we get 3168 // the bounding content rect and ask APZ to zoom in to the target content. 3169 if (caretInfo.frame) { 3170 presShell->ScrollFrameIntoView( 3171 caretInfo.frame, caretInfo.caretRectRelativeToTextFrame, 3172 ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotVisible), 3173 ScrollAxis(WhereToScroll::Center, WhenToScroll::IfNotVisible), 3174 ScrollFlags::ForZoomToFocusedInput); 3175 } 3176 3177 RefPtr<Document> document = presShell->GetDocument(); 3178 if (!document) { 3179 return NS_OK; 3180 } 3181 3182 uint32_t presShellId; 3183 ScrollableLayerGuid::ViewID viewId; 3184 if (!APZCCallbackHelper::GetOrCreateScrollIdentifiers( 3185 document->GetDocumentElement(), &presShellId, &viewId)) { 3186 return NS_OK; 3187 } 3188 3189 TouchBehaviorFlags tbf = 3190 layers::TouchActionHelper::GetAllowedTouchBehaviorForFrame( 3191 element->GetPrimaryFrame()); 3192 3193 uint32_t flags = layers::DISABLE_ZOOM_OUT | layers::ZOOM_TO_FOCUSED_INPUT; 3194 if (!Preferences::GetBool("formhelper.autozoom") || 3195 Preferences::GetBool("formhelper.autozoom.force-disable.test-only", 3196 /* aFallback = */ false) || 3197 !(tbf & AllowedTouchBehavior::ANIMATING_ZOOM)) { 3198 flags |= layers::PAN_INTO_VIEW_ONLY; 3199 } else { 3200 flags |= layers::ONLY_ZOOM_TO_DEFAULT_SCALE; 3201 } 3202 3203 if (caretInfo.textFrameBoundsRelativeToRootScroller.IsEmpty()) { 3204 // Do not zoom on empty bounds. Bail out. 3205 return NS_OK; 3206 } 3207 3208 caretInfo.textFrameBoundsRelativeToRootScroller -= 3209 CSSPoint::FromAppUnits(rootScrollContainerFrame->GetScrollPosition()); 3210 3211 bool waitForRefresh = false; 3212 for (ScrollContainerFrame* scrollAncestor : 3213 CollectScrollableAncestors(element->GetPrimaryFrame())) { 3214 if (scrollAncestor->HasScrollUpdates()) { 3215 waitForRefresh = true; 3216 break; 3217 } 3218 } 3219 APZZTFI_LOG("zooming to rect %s with flags %d, waitForRefresh=%d", 3220 ToString(caretInfo.textFrameBoundsRelativeToRootScroller).c_str(), 3221 flags, waitForRefresh); 3222 if (waitForRefresh) { 3223 waitForRefresh = false; 3224 if (nsPresContext* presContext = presShell->GetPresContext()) { 3225 waitForRefresh = true; 3226 presContext->RegisterManagedPostRefreshObserver( 3227 new ManagedPostRefreshObserver( 3228 presContext, 3229 [widget = RefPtr<nsIWidget>(widget), presShellId, viewId, 3230 bounds = caretInfo.textFrameBoundsRelativeToRootScroller, 3231 flags](bool aWasCanceled) { 3232 if (!aWasCanceled) { 3233 widget->ZoomToRect(presShellId, viewId, bounds, flags); 3234 } 3235 return ManagedPostRefreshObserver::Unregister::Yes; 3236 })); 3237 } 3238 } 3239 if (!waitForRefresh) { 3240 widget->ZoomToRect(presShellId, viewId, 3241 caretInfo.textFrameBoundsRelativeToRootScroller, flags); 3242 } 3243 3244 return NS_OK; 3245 } 3246 3247 NS_IMETHODIMP 3248 nsDOMWindowUtils::ComputeAnimationDistance(Element* aElement, 3249 const nsAString& aProperty, 3250 const nsAString& aValue1, 3251 const nsAString& aValue2, 3252 double* aResult) { 3253 NS_ENSURE_ARG_POINTER(aElement); 3254 3255 NS_ConvertUTF16toUTF8 prop(aProperty); 3256 3257 NonCustomCSSPropertyId propertyId = nsCSSProps::LookupProperty(prop); 3258 if (propertyId == eCSSProperty_UNKNOWN || 3259 nsCSSProps::IsShorthand(propertyId)) { 3260 return NS_ERROR_ILLEGAL_VALUE; 3261 } 3262 3263 auto property = CSSPropertyId::FromIdOrCustomProperty(propertyId, prop); 3264 3265 AnimationValue v1 = AnimationValue::FromString( 3266 property, NS_ConvertUTF16toUTF8(aValue1), aElement); 3267 AnimationValue v2 = AnimationValue::FromString( 3268 property, NS_ConvertUTF16toUTF8(aValue2), aElement); 3269 if (v1.IsNull() || v2.IsNull()) { 3270 return NS_ERROR_ILLEGAL_VALUE; 3271 } 3272 3273 *aResult = v1.ComputeDistance(v2); 3274 return NS_OK; 3275 } 3276 3277 NS_IMETHODIMP 3278 nsDOMWindowUtils::GetUnanimatedComputedStyle(Element* aElement, 3279 const nsAString& aPseudoElement, 3280 const nsAString& aProperty, 3281 int32_t aFlushType, 3282 nsAString& aResult) { 3283 if (!aElement) { 3284 return NS_ERROR_INVALID_ARG; 3285 } 3286 3287 NS_ConvertUTF16toUTF8 prop(aProperty); 3288 3289 NonCustomCSSPropertyId propertyId = nsCSSProps::LookupProperty(prop); 3290 if (propertyId == eCSSProperty_UNKNOWN || 3291 nsCSSProps::IsShorthand(propertyId)) { 3292 return NS_ERROR_INVALID_ARG; 3293 } 3294 3295 auto property = CSSPropertyId::FromIdOrCustomProperty(propertyId, prop); 3296 3297 switch (aFlushType) { 3298 case FLUSH_NONE: 3299 break; 3300 case FLUSH_STYLE: { 3301 if (Document* doc = aElement->GetComposedDoc()) { 3302 doc->FlushPendingNotifications(FlushType::Style); 3303 } 3304 break; 3305 } 3306 default: 3307 return NS_ERROR_INVALID_ARG; 3308 } 3309 3310 RefPtr<PresShell> presShell = GetPresShell(); 3311 if (!presShell) { 3312 return NS_ERROR_FAILURE; 3313 } 3314 3315 Maybe<PseudoStyleRequest> pseudo = 3316 nsCSSPseudoElements::ParsePseudoElement(aPseudoElement); 3317 if (!pseudo) { 3318 return NS_ERROR_FAILURE; 3319 } 3320 RefPtr<const ComputedStyle> computedStyle = 3321 nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(aElement, *pseudo); 3322 if (!computedStyle) { 3323 return NS_ERROR_FAILURE; 3324 } 3325 3326 RefPtr<StyleAnimationValue> value = 3327 Servo_ComputedValues_ExtractAnimationValue(computedStyle, &property) 3328 .Consume(); 3329 if (!value) { 3330 return NS_ERROR_FAILURE; 3331 } 3332 if (!aElement->GetComposedDoc()) { 3333 return NS_ERROR_FAILURE; 3334 } 3335 nsAutoCString result; 3336 Servo_AnimationValue_Serialize(value, &property, 3337 presShell->StyleSet()->RawData(), &result); 3338 CopyUTF8toUTF16(result, aResult); 3339 return NS_OK; 3340 } 3341 3342 NS_IMETHODIMP 3343 nsDOMWindowUtils::GetDisplayDPI(float* aDPI) { 3344 nsCOMPtr<nsIWidget> widget = GetWidget(); 3345 if (!widget) return NS_ERROR_FAILURE; 3346 3347 *aDPI = widget->GetDPI(); 3348 3349 return NS_OK; 3350 } 3351 3352 NS_IMETHODIMP 3353 nsDOMWindowUtils::CheckAndClearPaintedState(Element* aElement, bool* aResult) { 3354 if (!aElement) { 3355 return NS_ERROR_INVALID_ARG; 3356 } 3357 3358 nsIFrame* frame = aElement->GetPrimaryFrame(); 3359 3360 if (!frame) { 3361 *aResult = false; 3362 return NS_OK; 3363 } 3364 3365 // Get the outermost frame for the content node, so that we can test 3366 // canvasframe invalidations by observing the documentElement. 3367 for (;;) { 3368 nsIFrame* parentFrame = frame->GetParent(); 3369 if (parentFrame && parentFrame->GetContent() == aElement) { 3370 frame = parentFrame; 3371 } else { 3372 break; 3373 } 3374 } 3375 3376 while (frame) { 3377 if (!frame->CheckAndClearPaintedState()) { 3378 *aResult = false; 3379 return NS_OK; 3380 } 3381 frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame); 3382 } 3383 *aResult = true; 3384 return NS_OK; 3385 } 3386 3387 NS_IMETHODIMP 3388 nsDOMWindowUtils::CheckAndClearDisplayListState(Element* aElement, 3389 bool* aResult) { 3390 if (!aElement) { 3391 return NS_ERROR_INVALID_ARG; 3392 } 3393 3394 nsIFrame* frame = aElement->GetPrimaryFrame(); 3395 3396 if (!frame) { 3397 *aResult = false; 3398 return NS_OK; 3399 } 3400 3401 // Get the outermost frame for the content node, so that we can test 3402 // canvasframe invalidations by observing the documentElement. 3403 for (;;) { 3404 nsIFrame* parentFrame = frame->GetParent(); 3405 if (parentFrame && parentFrame->GetContent() == aElement) { 3406 frame = parentFrame; 3407 } else { 3408 break; 3409 } 3410 } 3411 3412 while (frame) { 3413 if (!frame->CheckAndClearDisplayListState()) { 3414 *aResult = false; 3415 return NS_OK; 3416 } 3417 frame = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(frame); 3418 } 3419 *aResult = true; 3420 return NS_OK; 3421 } 3422 3423 NS_IMETHODIMP 3424 nsDOMWindowUtils::EnableDialogs() { 3425 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 3426 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 3427 3428 nsGlobalWindowOuter::Cast(window)->EnableDialogs(); 3429 return NS_OK; 3430 } 3431 3432 NS_IMETHODIMP 3433 nsDOMWindowUtils::DisableDialogs() { 3434 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 3435 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 3436 3437 nsGlobalWindowOuter::Cast(window)->DisableDialogs(); 3438 return NS_OK; 3439 } 3440 3441 NS_IMETHODIMP 3442 nsDOMWindowUtils::AreDialogsEnabled(bool* aResult) { 3443 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 3444 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 3445 3446 *aResult = nsGlobalWindowOuter::Cast(window)->AreDialogsEnabled(); 3447 return NS_OK; 3448 } 3449 3450 NS_IMETHODIMP 3451 nsDOMWindowUtils::ResetDialogAbuseState() { 3452 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 3453 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 3454 3455 nsGlobalWindowOuter::Cast(window) 3456 ->GetBrowsingContextGroup() 3457 ->ResetDialogAbuseState(); 3458 return NS_OK; 3459 } 3460 3461 NS_IMETHODIMP 3462 nsDOMWindowUtils::GetFileId(JS::Handle<JS::Value> aFile, JSContext* aCx, 3463 int64_t* _retval) { 3464 if (aFile.isPrimitive()) { 3465 *_retval = -1; 3466 return NS_OK; 3467 } 3468 3469 JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull()); 3470 3471 Blob* blob = nullptr; 3472 if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) { 3473 *_retval = blob->GetFileId(); 3474 return NS_OK; 3475 } 3476 3477 *_retval = -1; 3478 return NS_OK; 3479 } 3480 3481 NS_IMETHODIMP 3482 nsDOMWindowUtils::GetFilePath(JS::Handle<JS::Value> aFile, JSContext* aCx, 3483 nsAString& _retval) { 3484 if (aFile.isPrimitive()) { 3485 _retval.Truncate(); 3486 return NS_OK; 3487 } 3488 3489 JS::Rooted<JSObject*> obj(aCx, aFile.toObjectOrNull()); 3490 3491 File* file = nullptr; 3492 if (NS_SUCCEEDED(UNWRAP_OBJECT(File, &obj, file))) { 3493 nsString filePath; 3494 ErrorResult rv; 3495 file->GetMozFullPathInternal(filePath, rv); 3496 if (NS_WARN_IF(rv.Failed())) { 3497 return rv.StealNSResult(); 3498 } 3499 3500 _retval = filePath; 3501 return NS_OK; 3502 } 3503 3504 _retval.Truncate(); 3505 return NS_OK; 3506 } 3507 3508 NS_IMETHODIMP 3509 nsDOMWindowUtils::GetFileReferences(const nsAString& aDatabaseName, int64_t aId, 3510 int32_t* aRefCnt, int32_t* aDBRefCnt, 3511 bool* aResult) { 3512 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 3513 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 3514 3515 quota::PrincipalMetadata principalMetadata = 3516 MOZ_TRY(quota::GetInfoFromWindow(window)); 3517 3518 RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get(); 3519 if (mgr) { 3520 nsresult rv = mgr->BlockAndGetFileReferences( 3521 principalMetadata.mIsPrivate ? quota::PERSISTENCE_TYPE_PRIVATE 3522 : quota::PERSISTENCE_TYPE_DEFAULT, 3523 principalMetadata.mOrigin, aDatabaseName, aId, aRefCnt, aDBRefCnt, 3524 aResult); 3525 3526 NS_ENSURE_SUCCESS(rv, rv); 3527 } else { 3528 *aRefCnt = *aDBRefCnt = -1; 3529 *aResult = false; 3530 } 3531 3532 return NS_OK; 3533 } 3534 3535 NS_IMETHODIMP 3536 nsDOMWindowUtils::FlushPendingFileDeletions() { 3537 RefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::Get(); 3538 if (mgr) { 3539 nsresult rv = mgr->FlushPendingFileDeletions(); 3540 if (NS_WARN_IF(NS_FAILED(rv))) { 3541 return rv; 3542 } 3543 } 3544 3545 return NS_OK; 3546 } 3547 3548 NS_IMETHODIMP 3549 nsDOMWindowUtils::StartPCCountProfiling(JSContext* cx) { 3550 JS::StartPCCountProfiling(cx); 3551 return NS_OK; 3552 } 3553 3554 NS_IMETHODIMP 3555 nsDOMWindowUtils::StopPCCountProfiling(JSContext* cx) { 3556 JS::StopPCCountProfiling(cx); 3557 return NS_OK; 3558 } 3559 3560 NS_IMETHODIMP 3561 nsDOMWindowUtils::PurgePCCounts(JSContext* cx) { 3562 JS::PurgePCCounts(cx); 3563 return NS_OK; 3564 } 3565 3566 NS_IMETHODIMP 3567 nsDOMWindowUtils::GetPCCountScriptCount(JSContext* cx, int32_t* result) { 3568 *result = JS::GetPCCountScriptCount(cx); 3569 return NS_OK; 3570 } 3571 3572 NS_IMETHODIMP 3573 nsDOMWindowUtils::GetPCCountScriptSummary(int32_t script, JSContext* cx, 3574 nsAString& result) { 3575 JSString* text = JS::GetPCCountScriptSummary(cx, script); 3576 if (!text) return NS_ERROR_FAILURE; 3577 3578 if (!AssignJSString(cx, result, text)) return NS_ERROR_FAILURE; 3579 3580 return NS_OK; 3581 } 3582 3583 NS_IMETHODIMP 3584 nsDOMWindowUtils::GetPCCountScriptContents(int32_t script, JSContext* cx, 3585 nsAString& result) { 3586 JSString* text = JS::GetPCCountScriptContents(cx, script); 3587 if (!text) return NS_ERROR_FAILURE; 3588 3589 if (!AssignJSString(cx, result, text)) return NS_ERROR_FAILURE; 3590 3591 return NS_OK; 3592 } 3593 3594 NS_IMETHODIMP 3595 nsDOMWindowUtils::GetPaintingSuppressed(bool* aPaintingSuppressed) { 3596 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 3597 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 3598 nsIDocShell* docShell = window->GetDocShell(); 3599 NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE); 3600 3601 PresShell* presShell = docShell->GetPresShell(); 3602 NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); 3603 3604 *aPaintingSuppressed = presShell->IsPaintingSuppressed(); 3605 return NS_OK; 3606 } 3607 3608 NS_IMETHODIMP 3609 nsDOMWindowUtils::SetVisualViewportSize(float aWidth, float aHeight) { 3610 if (!(aWidth >= 0.0 && aHeight >= 0.0)) { 3611 return NS_ERROR_ILLEGAL_VALUE; 3612 } 3613 3614 PresShell* presShell = GetPresShell(); 3615 if (!presShell) { 3616 return NS_ERROR_FAILURE; 3617 } 3618 3619 presShell->SetVisualViewportSize(nsPresContext::CSSPixelsToAppUnits(aWidth), 3620 nsPresContext::CSSPixelsToAppUnits(aHeight)); 3621 3622 return NS_OK; 3623 } 3624 3625 nsresult nsDOMWindowUtils::RemoteFrameFullscreenChanged( 3626 Element* aFrameElement) { 3627 nsCOMPtr<Document> doc = GetDocument(); 3628 NS_ENSURE_STATE(doc); 3629 3630 doc->RemoteFrameFullscreenChanged(aFrameElement); 3631 return NS_OK; 3632 } 3633 3634 nsresult nsDOMWindowUtils::RemoteFrameFullscreenReverted() { 3635 nsCOMPtr<Document> doc = GetDocument(); 3636 NS_ENSURE_STATE(doc); 3637 3638 doc->RemoteFrameFullscreenReverted(); 3639 return NS_OK; 3640 } 3641 3642 static void PrepareForFullscreenChange(nsIDocShell* aDocShell, 3643 const nsSize& aSize, 3644 nsSize* aOldSize = nullptr) { 3645 if (!aDocShell) { 3646 return; 3647 } 3648 PresShell* presShell = aDocShell->GetPresShell(); 3649 if (!presShell) { 3650 return; 3651 } 3652 if (nsRefreshDriver* rd = presShell->GetRefreshDriver()) { 3653 rd->SetIsResizeSuppressed(); 3654 // Since we are suppressing the resize reflow which would originally 3655 // be triggered by view manager, we need to ensure that the refresh 3656 // driver actually schedules a flush, otherwise it may get stuck. 3657 rd->SchedulePaint(); 3658 } 3659 if (!aSize.IsEmpty()) { 3660 nsCOMPtr<nsIDocumentViewer> viewer; 3661 aDocShell->GetDocViewer(getter_AddRefs(viewer)); 3662 if (viewer) { 3663 LayoutDeviceIntRect viewerBounds; 3664 viewer->GetBounds(viewerBounds); 3665 nscoord auPerDev = presShell->GetPresContext()->AppUnitsPerDevPixel(); 3666 if (aOldSize) { 3667 *aOldSize = 3668 LayoutDeviceIntSize::ToAppUnits(viewerBounds.Size(), auPerDev); 3669 } 3670 auto newSize = LayoutDeviceIntSize::FromAppUnitsRounded(aSize, auPerDev); 3671 viewerBounds.SizeTo(newSize.width, newSize.height); 3672 viewer->SetBounds(viewerBounds); 3673 } 3674 } 3675 } 3676 3677 NS_IMETHODIMP 3678 nsDOMWindowUtils::HandleFullscreenRequests(bool* aRetVal) { 3679 PROFILER_MARKER_UNTYPED("Enter fullscreen", DOM); 3680 nsCOMPtr<Document> doc = GetDocument(); 3681 NS_ENSURE_STATE(doc); 3682 3683 // Notify the pres shell that we are starting fullscreen change, and 3684 // set the window dimensions in advance. Since the resize message 3685 // comes after the fullscreen change call, doing so could avoid an 3686 // extra resize reflow after this point. 3687 nsRect screenRect; 3688 if (nsPresContext* presContext = GetPresContext()) { 3689 screenRect = presContext->DeviceContext()->GetRect(); 3690 } 3691 nsSize oldSize; 3692 PrepareForFullscreenChange(GetDocShell(), screenRect.Size(), &oldSize); 3693 OldWindowSize::Set(mWindow, oldSize); 3694 3695 *aRetVal = Document::HandlePendingFullscreenRequests(doc); 3696 return NS_OK; 3697 } 3698 3699 nsresult nsDOMWindowUtils::ExitFullscreen(bool aDontRestoreViewSize) { 3700 PROFILER_MARKER_UNTYPED("Exit fullscreen", DOM); 3701 nsCOMPtr<Document> doc = GetDocument(); 3702 NS_ENSURE_STATE(doc); 3703 3704 // Although we would not use the old size if we have already exited 3705 // fullscreen, we still want to cleanup in case we haven't. 3706 nsSize oldSize = OldWindowSize::GetAndRemove(mWindow); 3707 if (!doc->GetFullscreenElement()) { 3708 return NS_OK; 3709 } 3710 3711 // Notify the pres shell that we are starting fullscreen change, and 3712 // set the window dimensions in advance. Since the resize message 3713 // comes after the fullscreen change call, doing so could avoid an 3714 // extra resize reflow after this point. 3715 PrepareForFullscreenChange(GetDocShell(), 3716 aDontRestoreViewSize ? nsSize() : oldSize); 3717 Document::ExitFullscreenInDocTree(doc); 3718 return NS_OK; 3719 } 3720 3721 NS_IMETHODIMP 3722 nsDOMWindowUtils::SelectAtPoint(float aX, float aY, uint32_t aSelectBehavior, 3723 bool* _retval) { 3724 *_retval = false; 3725 3726 nsSelectionAmount amount; 3727 switch (aSelectBehavior) { 3728 case nsIDOMWindowUtils::SELECT_CHARACTER: 3729 amount = eSelectCharacter; 3730 break; 3731 case nsIDOMWindowUtils::SELECT_CLUSTER: 3732 amount = eSelectCluster; 3733 break; 3734 case nsIDOMWindowUtils::SELECT_WORD: 3735 amount = eSelectWord; 3736 break; 3737 case nsIDOMWindowUtils::SELECT_LINE: 3738 amount = eSelectLine; 3739 break; 3740 case nsIDOMWindowUtils::SELECT_BEGINLINE: 3741 amount = eSelectBeginLine; 3742 break; 3743 case nsIDOMWindowUtils::SELECT_ENDLINE: 3744 amount = eSelectEndLine; 3745 break; 3746 case nsIDOMWindowUtils::SELECT_PARAGRAPH: 3747 amount = eSelectParagraph; 3748 break; 3749 case nsIDOMWindowUtils::SELECT_WORDNOSPACE: 3750 amount = eSelectWordNoSpace; 3751 break; 3752 default: 3753 return NS_ERROR_INVALID_ARG; 3754 } 3755 3756 PresShell* presShell = GetPresShell(); 3757 if (!presShell) { 3758 return NS_ERROR_UNEXPECTED; 3759 } 3760 3761 // The root frame for this content window 3762 nsIFrame* rootFrame = presShell->GetRootFrame(); 3763 if (!rootFrame) { 3764 return NS_ERROR_UNEXPECTED; 3765 } 3766 3767 // Get the target frame at the client coordinates passed to us 3768 nsPoint offset; 3769 nsCOMPtr<nsIWidget> widget = GetWidget(&offset); 3770 LayoutDeviceIntPoint pt = 3771 nsContentUtils::ToWidgetPoint(CSSPoint(aX, aY), offset, GetPresContext()); 3772 nsPoint ptInRoot = nsLayoutUtils::GetEventCoordinatesRelativeTo( 3773 widget, pt, RelativeTo{rootFrame}); 3774 nsIFrame* targetFrame = 3775 nsLayoutUtils::GetFrameForPoint(RelativeTo{rootFrame}, ptInRoot); 3776 // This can happen if the page hasn't loaded yet or if the point 3777 // is outside the frame. 3778 if (!targetFrame) { 3779 return NS_ERROR_INVALID_ARG; 3780 } 3781 3782 // Convert point to coordinates relative to the target frame, which is 3783 // what targetFrame's SelectByTypeAtPoint expects. 3784 nsPoint relPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo( 3785 widget, pt, RelativeTo{targetFrame}); 3786 3787 nsresult rv = targetFrame->SelectByTypeAtPoint(relPoint, amount, amount, 3788 nsIFrame::SELECT_ACCUMULATE); 3789 *_retval = !NS_FAILED(rv); 3790 return NS_OK; 3791 } 3792 3793 static Document::additionalSheetType convertSheetType(uint32_t aSheetType) { 3794 switch (aSheetType) { 3795 case nsDOMWindowUtils::AGENT_SHEET: 3796 return Document::eAgentSheet; 3797 case nsDOMWindowUtils::USER_SHEET: 3798 return Document::eUserSheet; 3799 case nsDOMWindowUtils::AUTHOR_SHEET: 3800 return Document::eAuthorSheet; 3801 default: 3802 NS_ASSERTION(false, "wrong type"); 3803 // we must return something although this should never happen 3804 return Document::AdditionalSheetTypeCount; 3805 } 3806 } 3807 3808 NS_IMETHODIMP 3809 nsDOMWindowUtils::LoadSheet(nsIURI* aSheetURI, uint32_t aSheetType) { 3810 NS_ENSURE_ARG_POINTER(aSheetURI); 3811 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET || 3812 aSheetType == AUTHOR_SHEET); 3813 3814 nsCOMPtr<Document> doc = GetDocument(); 3815 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); 3816 3817 Document::additionalSheetType type = convertSheetType(aSheetType); 3818 3819 return doc->LoadAdditionalStyleSheet(type, aSheetURI); 3820 } 3821 3822 NS_IMETHODIMP 3823 nsDOMWindowUtils::LoadSheetUsingURIString(const nsACString& aSheetURI, 3824 uint32_t aSheetType) { 3825 nsCOMPtr<nsIURI> uri; 3826 nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI); 3827 NS_ENSURE_SUCCESS(rv, rv); 3828 3829 return LoadSheet(uri, aSheetType); 3830 } 3831 3832 NS_IMETHODIMP 3833 nsDOMWindowUtils::AddSheet(nsIPreloadedStyleSheet* aSheet, 3834 uint32_t aSheetType) { 3835 NS_ENSURE_ARG_POINTER(aSheet); 3836 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET || 3837 aSheetType == AUTHOR_SHEET); 3838 3839 nsCOMPtr<Document> doc = GetDocument(); 3840 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); 3841 3842 StyleSheet* sheet = 3843 MOZ_TRY(static_cast<PreloadedStyleSheet*>(aSheet)->GetSheet()); 3844 3845 Document::additionalSheetType type = convertSheetType(aSheetType); 3846 return doc->AddAdditionalStyleSheet(type, sheet); 3847 } 3848 3849 NS_IMETHODIMP 3850 nsDOMWindowUtils::RemoveSheet(nsIURI* aSheetURI, uint32_t aSheetType) { 3851 NS_ENSURE_ARG_POINTER(aSheetURI); 3852 NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET || 3853 aSheetType == AUTHOR_SHEET); 3854 3855 nsCOMPtr<Document> doc = GetDocument(); 3856 NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); 3857 3858 Document::additionalSheetType type = convertSheetType(aSheetType); 3859 3860 doc->RemoveAdditionalStyleSheet(type, aSheetURI); 3861 return NS_OK; 3862 } 3863 3864 NS_IMETHODIMP 3865 nsDOMWindowUtils::RemoveSheetUsingURIString(const nsACString& aSheetURI, 3866 uint32_t aSheetType) { 3867 nsCOMPtr<nsIURI> uri; 3868 nsresult rv = NS_NewURI(getter_AddRefs(uri), aSheetURI); 3869 NS_ENSURE_SUCCESS(rv, rv); 3870 3871 return RemoveSheet(uri, aSheetType); 3872 } 3873 3874 NS_IMETHODIMP 3875 nsDOMWindowUtils::GetIsHandlingUserInput(bool* aHandlingUserInput) { 3876 *aHandlingUserInput = UserActivation::IsHandlingUserInput(); 3877 3878 return NS_OK; 3879 } 3880 3881 NS_IMETHODIMP 3882 nsDOMWindowUtils::GetMillisSinceLastUserInput( 3883 double* aMillisSinceLastUserInput) { 3884 TimeStamp lastInput = UserActivation::LatestUserInputStart(); 3885 if (lastInput.IsNull()) { 3886 *aMillisSinceLastUserInput = -1.0f; 3887 return NS_OK; 3888 } 3889 3890 *aMillisSinceLastUserInput = (TimeStamp::Now() - lastInput).ToMilliseconds(); 3891 return NS_OK; 3892 } 3893 3894 NS_IMETHODIMP 3895 nsDOMWindowUtils::AllowScriptsToClose() { 3896 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 3897 NS_ENSURE_STATE(window); 3898 nsGlobalWindowOuter::Cast(window)->AllowScriptsToClose(); 3899 return NS_OK; 3900 } 3901 3902 NS_IMETHODIMP 3903 nsDOMWindowUtils::GetIsParentWindowMainWidgetVisible(bool* aIsVisible) { 3904 if (!XRE_IsParentProcess()) { 3905 MOZ_CRASH( 3906 "IsParentWindowMainWidgetVisible is only available in the parent " 3907 "process"); 3908 } 3909 3910 // this should reflect the "is parent window visible" logic in 3911 // nsWindowWatcher::OpenWindowInternal() 3912 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 3913 NS_ENSURE_STATE(window); 3914 3915 nsCOMPtr<nsIWidget> parentWidget; 3916 nsIDocShell* docShell = window->GetDocShell(); 3917 if (docShell) { 3918 nsCOMPtr<nsIDocShellTreeOwner> parentTreeOwner; 3919 docShell->GetTreeOwner(getter_AddRefs(parentTreeOwner)); 3920 nsCOMPtr<nsIBaseWindow> parentWindow(do_GetInterface(parentTreeOwner)); 3921 if (parentWindow) { 3922 parentWidget = parentWindow->GetMainWidget(); 3923 } 3924 } 3925 if (!parentWidget) { 3926 return NS_ERROR_NOT_AVAILABLE; 3927 } 3928 3929 *aIsVisible = parentWidget->IsVisible(); 3930 return NS_OK; 3931 } 3932 3933 NS_IMETHODIMP 3934 nsDOMWindowUtils::IsNodeDisabledForEvents(nsINode* aNode, bool* aRetVal) { 3935 *aRetVal = false; 3936 nsINode* node = aNode; 3937 while (node) { 3938 if (node->IsHTMLFormControlElement()) { 3939 nsGenericHTMLElement* element = nsGenericHTMLElement::FromNode(node); 3940 WidgetEvent event(true, eVoidEvent); 3941 if (element && element->IsDisabledForEvents(&event)) { 3942 *aRetVal = true; 3943 break; 3944 } 3945 } 3946 node = node->GetParentNode(); 3947 } 3948 3949 return NS_OK; 3950 } 3951 3952 NS_IMETHODIMP 3953 nsDOMWindowUtils::DispatchEventToChromeOnly(EventTarget* aTarget, Event* aEvent, 3954 bool* aRetVal) { 3955 *aRetVal = false; 3956 NS_ENSURE_STATE(aTarget && aEvent); 3957 aEvent->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true; 3958 *aRetVal = 3959 aTarget->DispatchEvent(*aEvent, CallerType::System, IgnoreErrors()); 3960 return NS_OK; 3961 } 3962 3963 static Result<nsIFrame*, nsresult> GetTargetFrame( 3964 const Element* aElement, const nsAString& aPseudoElement) { 3965 nsIFrame* frame = aElement->GetPrimaryFrame(); 3966 if (!aPseudoElement.IsEmpty()) { 3967 if (aPseudoElement.EqualsLiteral("::before")) { 3968 frame = nsLayoutUtils::GetBeforeFrame(aElement); 3969 } else if (aPseudoElement.EqualsLiteral("::after")) { 3970 frame = nsLayoutUtils::GetAfterFrame(aElement); 3971 } else { 3972 return Err(NS_ERROR_INVALID_ARG); 3973 } 3974 } 3975 return frame; 3976 } 3977 3978 static OMTAValue GetOMTAValue(nsIFrame* aFrame, DisplayItemType aDisplayItemKey, 3979 WebRenderBridgeChild* aWebRenderBridgeChild) { 3980 OMTAValue value = mozilla::null_t(); 3981 3982 if (aWebRenderBridgeChild) { 3983 RefPtr<WebRenderAnimationData> animationData = 3984 GetWebRenderUserData<WebRenderAnimationData>(aFrame, 3985 (uint32_t)aDisplayItemKey); 3986 if (animationData) { 3987 aWebRenderBridgeChild->SendGetAnimationValue( 3988 animationData->GetAnimationInfo().GetCompositorAnimationsId(), 3989 &value); 3990 } 3991 } 3992 return value; 3993 } 3994 3995 NS_IMETHODIMP 3996 nsDOMWindowUtils::GetOMTAStyle(Element* aElement, const nsAString& aProperty, 3997 const nsAString& aPseudoElement, 3998 nsAString& aResult) { 3999 if (!aElement) { 4000 return NS_ERROR_INVALID_ARG; 4001 } 4002 4003 auto frameOrError = GetTargetFrame(aElement, aPseudoElement); 4004 if (frameOrError.isErr()) { 4005 return frameOrError.unwrapErr(); 4006 } 4007 nsIFrame* frame = frameOrError.unwrap(); 4008 4009 RefPtr<nsROCSSPrimitiveValue> cssValue = nullptr; 4010 if (frame && nsLayoutUtils::AreAsyncAnimationsEnabled()) { 4011 if (aProperty.EqualsLiteral("opacity")) { 4012 OMTAValue value = GetOMTAValue(frame, DisplayItemType::TYPE_OPACITY, 4013 GetWebRenderBridge()); 4014 if (value.type() == OMTAValue::Tfloat) { 4015 cssValue = new nsROCSSPrimitiveValue; 4016 cssValue->SetNumber(value.get_float()); 4017 } 4018 } else if (aProperty.EqualsLiteral("transform") || 4019 aProperty.EqualsLiteral("translate") || 4020 aProperty.EqualsLiteral("rotate") || 4021 aProperty.EqualsLiteral("scale") || 4022 aProperty.EqualsLiteral("offset-path") || 4023 aProperty.EqualsLiteral("offset-distance") || 4024 aProperty.EqualsLiteral("offset-rotate") || 4025 aProperty.EqualsLiteral("offset-anchor") || 4026 aProperty.EqualsLiteral("offset-position")) { 4027 OMTAValue value = GetOMTAValue(frame, DisplayItemType::TYPE_TRANSFORM, 4028 GetWebRenderBridge()); 4029 if (value.type() == OMTAValue::TMatrix4x4) { 4030 cssValue = nsComputedDOMStyle::MatrixToCSSValue(value.get_Matrix4x4()); 4031 } 4032 } else if (aProperty.EqualsLiteral("background-color")) { 4033 OMTAValue value = GetOMTAValue( 4034 frame, DisplayItemType::TYPE_BACKGROUND_COLOR, GetWebRenderBridge()); 4035 if (value.type() == OMTAValue::Tnscolor) { 4036 nsStyleUtil::GetSerializedColorValue(value.get_nscolor(), aResult); 4037 return NS_OK; 4038 } 4039 } 4040 } 4041 4042 if (cssValue) { 4043 cssValue->GetCssText(aResult); 4044 return NS_OK; 4045 } 4046 aResult.Truncate(); 4047 return NS_OK; 4048 } 4049 4050 namespace { 4051 4052 class HandlingUserInputHelper final : public nsIJSRAIIHelper { 4053 public: 4054 explicit HandlingUserInputHelper(bool aHandlingUserInput); 4055 4056 NS_DECL_ISUPPORTS 4057 NS_DECL_NSIJSRAIIHELPER 4058 4059 private: 4060 ~HandlingUserInputHelper(); 4061 4062 bool mHandlingUserInput; 4063 bool mDestructCalled = false; 4064 }; 4065 4066 NS_IMPL_ISUPPORTS(HandlingUserInputHelper, nsIJSRAIIHelper) 4067 4068 HandlingUserInputHelper::HandlingUserInputHelper(bool aHandlingUserInput) 4069 : mHandlingUserInput(aHandlingUserInput) { 4070 if (aHandlingUserInput) { 4071 UserActivation::StartHandlingUserInput(eVoidEvent); 4072 } 4073 } 4074 4075 HandlingUserInputHelper::~HandlingUserInputHelper() { 4076 // We assert, but just in case, make sure we notify the ESM. 4077 MOZ_ASSERT(mDestructCalled); 4078 if (!mDestructCalled) { 4079 Destruct(); 4080 } 4081 } 4082 4083 NS_IMETHODIMP 4084 HandlingUserInputHelper::Destruct() { 4085 if (NS_WARN_IF(mDestructCalled)) { 4086 return NS_ERROR_FAILURE; 4087 } 4088 4089 mDestructCalled = true; 4090 if (mHandlingUserInput) { 4091 UserActivation::StopHandlingUserInput(eVoidEvent); 4092 } 4093 4094 return NS_OK; 4095 } 4096 4097 } // unnamed namespace 4098 4099 NS_IMETHODIMP 4100 nsDOMWindowUtils::SetHandlingUserInput(bool aHandlingUserInput, 4101 nsIJSRAIIHelper** aHelper) { 4102 if (aHandlingUserInput) { 4103 if (Document* doc = GetDocument()) { 4104 doc->NotifyUserGestureActivation(); 4105 } 4106 } 4107 auto helper = MakeRefPtr<HandlingUserInputHelper>(aHandlingUserInput); 4108 helper.forget(aHelper); 4109 return NS_OK; 4110 } 4111 4112 NS_IMETHODIMP 4113 nsDOMWindowUtils::IsKeyboardEventUserActivity(Event* aEvent, bool* aResult) { 4114 NS_ENSURE_STATE(aEvent); 4115 if (!aEvent->AsKeyboardEvent()) { 4116 return NS_ERROR_INVALID_ARG; 4117 } 4118 4119 WidgetEvent* internalEvent = aEvent->WidgetEventPtr(); 4120 NS_ENSURE_STATE(internalEvent); 4121 *aResult = EventStateManager::IsKeyboardEventUserActivity(internalEvent); 4122 return NS_OK; 4123 } 4124 4125 NS_IMETHODIMP 4126 nsDOMWindowUtils::GetContentAPZTestData( 4127 Element* aElement, JSContext* aContext, 4128 JS::MutableHandle<JS::Value> aOutContentTestData) { 4129 if (nsIWidget* widget = GetWidgetForElement(aElement)) { 4130 WindowRenderer* renderer = widget->GetWindowRenderer(); 4131 if (!renderer) { 4132 return NS_OK; 4133 } 4134 if (WebRenderLayerManager* wr = renderer->AsWebRender()) { 4135 if (!wr->GetAPZTestData().ToJS(aOutContentTestData, aContext)) { 4136 return NS_ERROR_FAILURE; 4137 } 4138 } 4139 } 4140 4141 return NS_OK; 4142 } 4143 4144 NS_IMETHODIMP 4145 nsDOMWindowUtils::GetCompositorAPZTestData( 4146 Element* aElement, JSContext* aContext, 4147 JS::MutableHandle<JS::Value> aOutCompositorTestData) { 4148 if (nsIWidget* widget = GetWidgetForElement(aElement)) { 4149 WindowRenderer* renderer = widget->GetWindowRenderer(); 4150 if (!renderer) { 4151 return NS_OK; 4152 } 4153 APZTestData compositorSideData; 4154 if (WebRenderLayerManager* wr = renderer->AsWebRender()) { 4155 if (!wr->WrBridge()) { 4156 return NS_ERROR_UNEXPECTED; 4157 } 4158 if (!wr->WrBridge()->SendGetAPZTestData(&compositorSideData)) { 4159 return NS_ERROR_FAILURE; 4160 } 4161 } 4162 if (!compositorSideData.ToJS(aOutCompositorTestData, aContext)) { 4163 return NS_ERROR_FAILURE; 4164 } 4165 } 4166 4167 return NS_OK; 4168 } 4169 4170 NS_IMETHODIMP 4171 nsDOMWindowUtils::PostRestyleSelfEvent(Element* aElement) { 4172 if (!aElement) { 4173 return NS_ERROR_INVALID_ARG; 4174 } 4175 4176 nsLayoutUtils::PostRestyleEvent(aElement, RestyleHint::RESTYLE_SELF, 4177 nsChangeHint(0)); 4178 return NS_OK; 4179 } 4180 4181 NS_IMETHODIMP 4182 nsDOMWindowUtils::SetCustomTitlebar(bool aCustomTitlebar) { 4183 // TODO(emilio): Can't we use nsDOMWindowUtils::GetWidget()? 4184 if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow)) { 4185 if (nsCOMPtr<nsIBaseWindow> baseWindow = 4186 do_QueryInterface(window->GetDocShell())) { 4187 if (nsCOMPtr<nsIWidget> widget = baseWindow->GetMainWidget()) { 4188 widget->SetCustomTitlebar(aCustomTitlebar); 4189 } 4190 } 4191 } 4192 return NS_OK; 4193 } 4194 4195 NS_IMETHODIMP 4196 nsDOMWindowUtils::SetResizeMargin(int32_t aResizeMargin) { 4197 // TODO(emilio): Can't we use nsDOMWindowUtils::GetWidget()? 4198 if (nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow)) { 4199 if (nsCOMPtr<nsIBaseWindow> baseWindow = 4200 do_QueryInterface(window->GetDocShell())) { 4201 if (nsCOMPtr<nsIWidget> widget = baseWindow->GetMainWidget()) { 4202 CSSToLayoutDeviceScale scaleFactor = widget->GetDefaultScale(); 4203 widget->SetResizeMargin( 4204 (CSSCoord(float(aResizeMargin)) * scaleFactor).Rounded()); 4205 } 4206 } 4207 } 4208 4209 return NS_OK; 4210 } 4211 4212 NS_IMETHODIMP 4213 nsDOMWindowUtils::GetFrameUniformityTestData( 4214 JSContext* aContext, JS::MutableHandle<JS::Value> aOutFrameUniformity) { 4215 nsIWidget* widget = GetWidget(); 4216 if (!widget) { 4217 return NS_ERROR_NOT_AVAILABLE; 4218 } 4219 4220 WindowRenderer* renderer = widget->GetWindowRenderer(); 4221 if (!renderer) { 4222 return NS_ERROR_NOT_AVAILABLE; 4223 } 4224 4225 FrameUniformityData outData; 4226 renderer->GetFrameUniformity(&outData); 4227 outData.ToJS(aOutFrameUniformity, aContext); 4228 return NS_OK; 4229 } 4230 4231 NS_IMETHODIMP 4232 nsDOMWindowUtils::XpconnectArgument(nsISupports* aObj) { 4233 // Do nothing. 4234 return NS_OK; 4235 } 4236 4237 NS_IMETHODIMP 4238 nsDOMWindowUtils::AskPermission(nsIContentPermissionRequest* aRequest) { 4239 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 4240 return nsContentPermissionUtils::AskPermission( 4241 aRequest, window->GetCurrentInnerWindow()); 4242 } 4243 4244 NS_IMETHODIMP 4245 nsDOMWindowUtils::GetRestyleGeneration(uint64_t* aResult) { 4246 nsPresContext* presContext = GetPresContext(); 4247 if (!presContext) { 4248 return NS_ERROR_NOT_AVAILABLE; 4249 } 4250 4251 *aResult = presContext->GetRestyleGeneration(); 4252 return NS_OK; 4253 } 4254 4255 NS_IMETHODIMP 4256 nsDOMWindowUtils::GetFramesConstructed(uint64_t* aResult) { 4257 nsPresContext* presContext = GetPresContext(); 4258 if (!presContext) { 4259 return NS_ERROR_NOT_AVAILABLE; 4260 } 4261 4262 *aResult = presContext->FramesConstructedCount(); 4263 return NS_OK; 4264 } 4265 4266 NS_IMETHODIMP 4267 nsDOMWindowUtils::GetFramesReflowed(uint64_t* aResult) { 4268 nsPresContext* presContext = GetPresContext(); 4269 if (!presContext) { 4270 return NS_ERROR_NOT_AVAILABLE; 4271 } 4272 4273 *aResult = presContext->FramesReflowedCount(); 4274 return NS_OK; 4275 } 4276 4277 NS_IMETHODIMP 4278 nsDOMWindowUtils::GetAnimationTriggeredRestyles(uint64_t* aResult) { 4279 nsPresContext* presContext = GetPresContext(); 4280 if (!presContext) { 4281 return NS_ERROR_NOT_AVAILABLE; 4282 } 4283 4284 *aResult = presContext->AnimationTriggeredRestylesCount(); 4285 return NS_OK; 4286 } 4287 4288 NS_IMETHODIMP 4289 nsDOMWindowUtils::GetRefreshDriverHasPendingTick(bool* aResult) { 4290 nsPresContext* presContext = GetPresContext(); 4291 if (!presContext) { 4292 return NS_ERROR_NOT_AVAILABLE; 4293 } 4294 4295 *aResult = presContext->RefreshDriver()->HasPendingTick(); 4296 return NS_OK; 4297 } 4298 4299 NS_IMETHODIMP 4300 nsDOMWindowUtils::EnterChaosMode() { 4301 ChaosMode::enterChaosMode(); 4302 return NS_OK; 4303 } 4304 4305 NS_IMETHODIMP 4306 nsDOMWindowUtils::LeaveChaosMode() { 4307 ChaosMode::leaveChaosMode(); 4308 return NS_OK; 4309 } 4310 4311 NS_IMETHODIMP 4312 nsDOMWindowUtils::TriggerDeviceReset() { 4313 if (!XRE_IsParentProcess()) { 4314 return NS_ERROR_NOT_AVAILABLE; 4315 } 4316 4317 GPUProcessManager* pm = GPUProcessManager::Get(); 4318 if (pm) { 4319 pm->SimulateDeviceReset(); 4320 } 4321 return NS_OK; 4322 } 4323 4324 NS_IMETHODIMP 4325 nsDOMWindowUtils::HasRuleProcessorUsedByMultipleStyleSets(uint32_t aSheetType, 4326 bool* aRetVal) { 4327 PresShell* presShell = GetPresShell(); 4328 if (!presShell) { 4329 return NS_ERROR_FAILURE; 4330 } 4331 4332 return presShell->HasRuleProcessorUsedByMultipleStyleSets(aSheetType, 4333 aRetVal); 4334 } 4335 4336 NS_IMETHODIMP 4337 nsDOMWindowUtils::RespectDisplayPortSuppression(bool aEnabled) { 4338 RefPtr<PresShell> presShell = GetPresShell(); 4339 presShell->RespectDisplayportSuppression(aEnabled); 4340 return NS_OK; 4341 } 4342 4343 NS_IMETHODIMP 4344 nsDOMWindowUtils::ForceReflowInterrupt() { 4345 nsPresContext* pc = GetPresContext(); 4346 if (!pc) { 4347 return NS_ERROR_NOT_AVAILABLE; 4348 } 4349 pc->SetPendingInterruptFromTest(); 4350 return NS_OK; 4351 } 4352 4353 NS_IMETHODIMP 4354 nsDOMWindowUtils::TerminateGPUProcess() { 4355 GPUProcessManager* pm = GPUProcessManager::Get(); 4356 if (pm) { 4357 pm->KillProcess(); 4358 } 4359 return NS_OK; 4360 } 4361 4362 NS_IMETHODIMP 4363 nsDOMWindowUtils::GetGpuProcessPid(int32_t* aPid) { 4364 GPUProcessManager* pm = GPUProcessManager::Get(); 4365 if (pm) { 4366 *aPid = pm->GPUProcessPid(); 4367 } else { 4368 *aPid = -1; 4369 } 4370 4371 return NS_OK; 4372 } 4373 4374 NS_IMETHODIMP 4375 nsDOMWindowUtils::GetRddProcessPid(int32_t* aPid) { 4376 RDDProcessManager* pm = RDDProcessManager::Get(); 4377 if (pm) { 4378 *aPid = pm->RDDProcessPid(); 4379 } else { 4380 *aPid = -1; 4381 } 4382 4383 return NS_OK; 4384 } 4385 4386 struct StateTableEntry { 4387 const char* mStateString; 4388 ElementState mState; 4389 }; 4390 4391 NS_IMETHODIMP 4392 nsDOMWindowUtils::GetStorageUsage(Storage* aStorage, int64_t* aRetval) { 4393 if (!aStorage) { 4394 return NS_ERROR_UNEXPECTED; 4395 } 4396 4397 *aRetval = aStorage->GetOriginQuotaUsage(); 4398 4399 return NS_OK; 4400 } 4401 4402 NS_IMETHODIMP 4403 nsDOMWindowUtils::GetDirectionFromText(const nsAString& aString, 4404 int32_t* aRetval) { 4405 Directionality dir = 4406 ::GetDirectionFromText(aString.BeginReading(), aString.Length(), nullptr); 4407 switch (dir) { 4408 case Directionality::Unset: 4409 *aRetval = nsIDOMWindowUtils::DIRECTION_NOT_SET; 4410 break; 4411 case Directionality::Rtl: 4412 *aRetval = nsIDOMWindowUtils::DIRECTION_RTL; 4413 break; 4414 case Directionality::Ltr: 4415 *aRetval = nsIDOMWindowUtils::DIRECTION_LTR; 4416 break; 4417 case Directionality::Auto: 4418 MOZ_ASSERT_UNREACHABLE( 4419 "GetDirectionFromText should never return this value"); 4420 return NS_ERROR_FAILURE; 4421 } 4422 return NS_OK; 4423 } 4424 4425 NS_IMETHODIMP 4426 nsDOMWindowUtils::EnsureDirtyRootFrame() { 4427 Document* doc = GetDocument(); 4428 PresShell* presShell = doc ? doc->GetPresShell() : nullptr; 4429 4430 if (!presShell) { 4431 return NS_ERROR_FAILURE; 4432 } 4433 4434 nsIFrame* frame = presShell->GetRootFrame(); 4435 if (!frame) { 4436 return NS_ERROR_FAILURE; 4437 } 4438 4439 presShell->FrameNeedsReflow( 4440 frame, IntrinsicDirty::FrameAncestorsAndDescendants, NS_FRAME_IS_DIRTY); 4441 return NS_OK; 4442 } 4443 4444 NS_INTERFACE_MAP_BEGIN(nsTranslationNodeList) 4445 NS_INTERFACE_MAP_ENTRY(nsISupports) 4446 NS_INTERFACE_MAP_ENTRY(nsITranslationNodeList) 4447 NS_INTERFACE_MAP_END 4448 4449 NS_IMPL_ADDREF(nsTranslationNodeList) 4450 NS_IMPL_RELEASE(nsTranslationNodeList) 4451 4452 NS_IMETHODIMP 4453 nsTranslationNodeList::Item(uint32_t aIndex, nsINode** aRetVal) { 4454 NS_ENSURE_ARG_POINTER(aRetVal); 4455 NS_IF_ADDREF(*aRetVal = mNodes.SafeElementAt(aIndex)); 4456 return NS_OK; 4457 } 4458 4459 NS_IMETHODIMP 4460 nsTranslationNodeList::IsTranslationRootAtIndex(uint32_t aIndex, 4461 bool* aRetVal) { 4462 NS_ENSURE_ARG_POINTER(aRetVal); 4463 if (aIndex >= mLength) { 4464 *aRetVal = false; 4465 return NS_OK; 4466 } 4467 4468 *aRetVal = mNodeIsRoot.ElementAt(aIndex); 4469 return NS_OK; 4470 } 4471 4472 NS_IMETHODIMP 4473 nsTranslationNodeList::GetLength(uint32_t* aRetVal) { 4474 NS_ENSURE_ARG_POINTER(aRetVal); 4475 *aRetVal = mLength; 4476 return NS_OK; 4477 } 4478 4479 NS_IMETHODIMP 4480 nsDOMWindowUtils::WrCapture() { 4481 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) { 4482 wrbc->Capture(); 4483 } 4484 return NS_OK; 4485 } 4486 4487 NS_IMETHODIMP 4488 nsDOMWindowUtils::WrStartCaptureSequence(const nsACString& aPath, 4489 uint32_t aFlags) { 4490 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) { 4491 wrbc->StartCaptureSequence(nsCString(aPath), aFlags); 4492 } 4493 return NS_OK; 4494 } 4495 4496 NS_IMETHODIMP 4497 nsDOMWindowUtils::WrStopCaptureSequence() { 4498 if (WebRenderBridgeChild* wrbc = GetWebRenderBridge()) { 4499 wrbc->StopCaptureSequence(); 4500 } 4501 return NS_OK; 4502 } 4503 4504 NS_IMETHODIMP 4505 nsDOMWindowUtils::SetCompositionRecording(bool aValue, Promise** aOutPromise) { 4506 return aValue ? StartCompositionRecording(aOutPromise) 4507 : StopCompositionRecording(true, aOutPromise); 4508 } 4509 4510 NS_IMETHODIMP 4511 nsDOMWindowUtils::StartCompositionRecording(Promise** aOutPromise) { 4512 NS_ENSURE_ARG(aOutPromise); 4513 *aOutPromise = nullptr; 4514 4515 nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow); 4516 NS_ENSURE_STATE(outer); 4517 nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow(); 4518 NS_ENSURE_STATE(inner); 4519 4520 ErrorResult err; 4521 RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err); 4522 if (NS_WARN_IF(err.Failed())) { 4523 return err.StealNSResult(); 4524 } 4525 4526 CompositorBridgeChild* cbc = GetCompositorBridge(); 4527 if (NS_WARN_IF(!cbc)) { 4528 promise->MaybeReject(NS_ERROR_UNEXPECTED); 4529 } else { 4530 cbc->SendBeginRecording(TimeStamp::Now()) 4531 ->Then( 4532 GetCurrentSerialEventTarget(), __func__, 4533 [promise](const bool& aSuccess) { 4534 if (aSuccess) { 4535 promise->MaybeResolve(true); 4536 } else { 4537 promise->MaybeRejectWithInvalidStateError( 4538 "The composition recorder is already running."); 4539 } 4540 }, 4541 [promise](const mozilla::ipc::ResponseRejectReason&) { 4542 promise->MaybeRejectWithInvalidStateError( 4543 "Could not start the composition recorder."); 4544 }); 4545 } 4546 4547 promise.forget(aOutPromise); 4548 return NS_OK; 4549 } 4550 4551 static bool WriteRecordingToDisk(const FrameRecording& aRecording, 4552 double aUnixStartMS) { 4553 // The directory name contains the unix timestamp for when recording started, 4554 // because we want the consumer of these files to be able to compute an 4555 // absolute timestamp of each screenshot. That allows them to align 4556 // screenshots with timed data from other sources, such as Gecko profiler 4557 // information. The time of each screenshot is part of the screenshot's 4558 // filename, expressed as milliseconds from the recording start. 4559 std::stringstream recordingDirectory; 4560 recordingDirectory << gfxVars::LayersWindowRecordingPath() 4561 << "windowrecording-" << int64_t(aUnixStartMS); 4562 4563 #ifdef XP_WIN 4564 _mkdir(recordingDirectory.str().c_str()); 4565 #else 4566 mkdir(recordingDirectory.str().c_str(), 0777); 4567 #endif 4568 4569 auto byteSpan = aRecording.bytes().AsSpan(); 4570 4571 uint32_t i = 1; 4572 4573 for (const auto& frame : aRecording.frames()) { 4574 const uint32_t frameBufferLength = frame.length(); 4575 if (frameBufferLength > byteSpan.Length()) { 4576 return false; 4577 } 4578 4579 const auto frameSpan = byteSpan.To(frameBufferLength); 4580 byteSpan = byteSpan.From(frameBufferLength); 4581 4582 const double frameTimeMS = 4583 (frame.timeOffset() - aRecording.startTime()).ToMilliseconds(); 4584 4585 std::stringstream filename; 4586 filename << recordingDirectory.str() << "/frame-" << i << "-" 4587 << uint32_t(frameTimeMS) << ".png"; 4588 4589 FILE* file = fopen(filename.str().c_str(), "wb"); 4590 if (!file) { 4591 return false; 4592 } 4593 4594 const size_t bytesWritten = 4595 fwrite(frameSpan.Elements(), sizeof(uint8_t), frameSpan.Length(), file); 4596 4597 fclose(file); 4598 4599 if (bytesWritten < frameSpan.Length()) { 4600 return false; 4601 } 4602 4603 ++i; 4604 } 4605 4606 return byteSpan.Length() == 0; 4607 } 4608 4609 static Maybe<DOMCollectedFrames> ConvertCompositionRecordingFramesToDom( 4610 const FrameRecording& aRecording, double aUnixStartMS) { 4611 auto byteSpan = aRecording.bytes().AsSpan(); 4612 4613 nsTArray<DOMCollectedFrame> domFrames; 4614 4615 for (const auto& recordedFrame : aRecording.frames()) { 4616 const uint32_t frameBufferLength = recordedFrame.length(); 4617 if (frameBufferLength > byteSpan.Length()) { 4618 return Nothing(); 4619 } 4620 4621 const auto frameSpan = byteSpan.To(frameBufferLength); 4622 byteSpan = byteSpan.From(frameBufferLength); 4623 4624 nsCString dataUri; 4625 4626 dataUri.AppendLiteral("data:image/png;base64,"); 4627 4628 nsresult rv = 4629 Base64EncodeAppend(reinterpret_cast<const char*>(frameSpan.Elements()), 4630 frameSpan.Length(), dataUri); 4631 if (NS_FAILED(rv)) { 4632 return Nothing(); 4633 } 4634 4635 DOMCollectedFrame domFrame; 4636 domFrame.mTimeOffset = 4637 (recordedFrame.timeOffset() - aRecording.startTime()).ToMilliseconds(); 4638 domFrame.mDataUri = std::move(dataUri); 4639 4640 domFrames.AppendElement(std::move(domFrame)); 4641 } 4642 4643 if (byteSpan.Length() != 0) { 4644 return Nothing(); 4645 } 4646 4647 DOMCollectedFrames result; 4648 4649 result.mRecordingStart = aUnixStartMS; 4650 result.mFrames = std::move(domFrames); 4651 4652 return Some(std::move(result)); 4653 } 4654 4655 NS_IMETHODIMP 4656 nsDOMWindowUtils::StopCompositionRecording(bool aWriteToDisk, 4657 Promise** aOutPromise) { 4658 NS_ENSURE_ARG_POINTER(aOutPromise); 4659 *aOutPromise = nullptr; 4660 4661 nsCOMPtr<nsPIDOMWindowOuter> outer = do_QueryReferent(mWindow); 4662 NS_ENSURE_STATE(outer); 4663 nsCOMPtr<nsPIDOMWindowInner> inner = outer->GetCurrentInnerWindow(); 4664 NS_ENSURE_STATE(inner); 4665 4666 ErrorResult err; 4667 RefPtr<Promise> promise = Promise::Create(inner->AsGlobal(), err); 4668 if (NS_WARN_IF(err.Failed())) { 4669 return err.StealNSResult(); 4670 } 4671 4672 RefPtr<Promise>(promise).forget(aOutPromise); 4673 4674 CompositorBridgeChild* cbc = GetCompositorBridge(); 4675 if (NS_WARN_IF(!cbc)) { 4676 promise->MaybeReject(NS_ERROR_UNEXPECTED); 4677 return NS_OK; 4678 } 4679 4680 cbc->SendEndRecording()->Then( 4681 GetCurrentSerialEventTarget(), __func__, 4682 [promise, aWriteToDisk](Maybe<FrameRecording>&& aRecording) { 4683 if (!aRecording) { 4684 promise->MaybeRejectWithUnknownError("Failed to get frame recording"); 4685 return; 4686 } 4687 4688 // We need to know when the recording started in Unix Time. 4689 // Unfortunately, the recording start time is an opaque Timestamp that 4690 // can only be used to calculate a duration. 4691 // 4692 // This is not great, but we are going to get Now() twice in close 4693 // proximity, one in Unix Time and the other in Timestamp time. Then we 4694 // can subtract the length of the recording from the current Unix Time 4695 // to get the Unix start time. 4696 const TimeStamp timestampNow = TimeStamp::Now(); 4697 const int64_t unixNowUS = PR_Now(); 4698 4699 const TimeDuration recordingLength = 4700 timestampNow - aRecording->startTime(); 4701 const double unixNowMS = double(unixNowUS) / 1000.0; 4702 const double unixStartMS = unixNowMS - recordingLength.ToMilliseconds(); 4703 4704 if (aWriteToDisk) { 4705 if (!WriteRecordingToDisk(*aRecording, unixStartMS)) { 4706 promise->MaybeRejectWithUnknownError( 4707 "Failed to write recording to disk"); 4708 return; 4709 } 4710 promise->MaybeResolveWithUndefined(); 4711 } else { 4712 auto maybeDomFrames = 4713 ConvertCompositionRecordingFramesToDom(*aRecording, unixStartMS); 4714 if (!maybeDomFrames) { 4715 promise->MaybeRejectWithUnknownError( 4716 "Unable to base64-encode recorded frames"); 4717 return; 4718 } 4719 promise->MaybeResolve(*maybeDomFrames); 4720 } 4721 }, 4722 [promise](const mozilla::ipc::ResponseRejectReason&) { 4723 promise->MaybeRejectWithUnknownError( 4724 "IPC failed getting composition recording"); 4725 }); 4726 4727 return NS_OK; 4728 } 4729 4730 NS_IMETHODIMP 4731 nsDOMWindowUtils::SetSystemFont(const nsACString& aFontName) { 4732 nsIWidget* widget = GetWidget(); 4733 if (!widget) { 4734 return NS_OK; 4735 } 4736 4737 nsAutoCString fontName(aFontName); 4738 return widget->SetSystemFont(fontName); 4739 } 4740 4741 NS_IMETHODIMP 4742 nsDOMWindowUtils::GetSystemFont(nsACString& aFontName) { 4743 nsIWidget* widget = GetWidget(); 4744 if (!widget) { 4745 return NS_OK; 4746 } 4747 4748 nsAutoCString fontName; 4749 widget->GetSystemFont(fontName); 4750 aFontName.Assign(fontName); 4751 return NS_OK; 4752 } 4753 4754 NS_IMETHODIMP 4755 nsDOMWindowUtils::IsCssPropertyRecordedInUseCounter(const nsACString& aPropName, 4756 bool* aRecorded) { 4757 *aRecorded = false; 4758 4759 Document* doc = GetDocument(); 4760 if (!doc || !doc->GetStyleUseCounters()) { 4761 return NS_ERROR_FAILURE; 4762 } 4763 4764 bool knownProp = false; 4765 *aRecorded = Servo_IsCssPropertyRecordedInUseCounter( 4766 doc->GetStyleUseCounters(), &aPropName, &knownProp); 4767 return knownProp ? NS_OK : NS_ERROR_FAILURE; 4768 } 4769 4770 NS_IMETHODIMP 4771 nsDOMWindowUtils::IsCoepCredentialless(bool* aResult) { 4772 Document* doc = GetDocument(); 4773 if (!doc) { 4774 return NS_ERROR_FAILURE; 4775 } 4776 4777 *aResult = net::IsCoepCredentiallessEnabled( 4778 doc->Trials().IsEnabled(OriginTrial::CoepCredentialless)); 4779 return NS_OK; 4780 } 4781 4782 NS_IMETHODIMP 4783 nsDOMWindowUtils::GetLayersId(Element* aElement, uint64_t* aOutLayersId) { 4784 nsIWidget* widget = GetWidgetForElement(aElement); 4785 if (!widget) { 4786 return NS_ERROR_FAILURE; 4787 } 4788 *aOutLayersId = (uint64_t)widget->GetLayersId(); 4789 return NS_OK; 4790 } 4791 4792 NS_IMETHODIMP 4793 nsDOMWindowUtils::GetPaintCount(uint64_t* aPaintCount) { 4794 auto* presShell = GetPresShell(); 4795 *aPaintCount = presShell ? presShell->GetPaintCount() : 0; 4796 return NS_OK; 4797 } 4798 4799 NS_IMETHODIMP 4800 nsDOMWindowUtils::GetWebrtcRawDeviceId(nsAString& aRawDeviceId) { 4801 if (!XRE_IsParentProcess()) { 4802 MOZ_CRASH( 4803 "GetWebrtcRawDeviceId is only available in the parent " 4804 "process"); 4805 } 4806 4807 nsIWidget* widget = GetWidget(); 4808 if (!widget) { 4809 return NS_ERROR_FAILURE; 4810 } 4811 4812 int64_t rawDeviceId = 4813 (int64_t)(widget->GetNativeData(NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID)); 4814 if (!rawDeviceId) { 4815 return NS_ERROR_FAILURE; 4816 } 4817 4818 aRawDeviceId.AppendInt(rawDeviceId); 4819 return NS_OK; 4820 } 4821 4822 NS_IMETHODIMP 4823 nsDOMWindowUtils::GetEffectivelyThrottlesFrameRequests(bool* aResult) { 4824 Document* doc = GetDocument(); 4825 if (!doc) { 4826 return NS_ERROR_FAILURE; 4827 } 4828 *aResult = doc->IsRenderingSuppressed() || doc->ShouldThrottleFrameRequests(); 4829 return NS_OK; 4830 } 4831 4832 NS_IMETHODIMP 4833 nsDOMWindowUtils::ResetMobileViewportManager() { 4834 if (RefPtr<PresShell> presShell = GetPresShell()) { 4835 if (auto mvm = presShell->GetMobileViewportManager()) { 4836 mvm->SetInitialViewport(); 4837 return NS_OK; 4838 } 4839 } 4840 // Unable to reset, so let's error out 4841 return NS_ERROR_FAILURE; 4842 } 4843 4844 NS_IMETHODIMP 4845 nsDOMWindowUtils::GetSuspendedByBrowsingContextGroup(bool* aResult) { 4846 nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryReferent(mWindow); 4847 NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); 4848 4849 nsCOMPtr<nsPIDOMWindowInner> inner = window->GetCurrentInnerWindow(); 4850 NS_ENSURE_TRUE(inner, NS_ERROR_FAILURE); 4851 4852 *aResult = inner->GetWasSuspendedByGroup(); 4853 return NS_OK; 4854 } 4855 4856 NS_IMETHODIMP 4857 nsDOMWindowUtils::GetHasScrollLinkedEffect(bool* aResult) { 4858 Document* doc = GetDocument(); 4859 if (!doc) { 4860 return NS_ERROR_FAILURE; 4861 } 4862 *aResult = doc->HasScrollLinkedEffect(); 4863 return NS_OK; 4864 } 4865 4866 NS_IMETHODIMP 4867 nsDOMWindowUtils::GetOrientationLock(uint32_t* aOrientationLock) { 4868 NS_WARNING("nsDOMWindowUtils::GetOrientationLock"); 4869 4870 nsIDocShell* docShell = GetDocShell(); 4871 if (!docShell) { 4872 return NS_ERROR_FAILURE; 4873 } 4874 4875 BrowsingContext* bc = docShell->GetBrowsingContext(); 4876 bc = bc ? bc->Top() : nullptr; 4877 if (!bc) { 4878 return NS_ERROR_FAILURE; 4879 } 4880 4881 *aOrientationLock = static_cast<uint32_t>(bc->GetOrientationLock()); 4882 return NS_OK; 4883 } 4884 4885 NS_IMETHODIMP 4886 nsDOMWindowUtils::GetWheelScrollTarget(Element** aResult) { 4887 *aResult = nullptr; 4888 if (nsIFrame* targetFrame = WheelTransaction::GetScrollTargetFrame()) { 4889 NS_IF_ADDREF(*aResult = Element::FromNodeOrNull(targetFrame->GetContent())); 4890 } 4891 return NS_OK; 4892 } 4893 4894 NS_IMETHODIMP 4895 nsDOMWindowUtils::SetHiDPIMode(bool aHiDPI) { 4896 #ifdef DEBUG 4897 nsCOMPtr<nsIWidget> widget = GetWidget(); 4898 if (!widget) return NS_ERROR_FAILURE; 4899 4900 return widget->SetHiDPIMode(aHiDPI); 4901 #else 4902 return NS_ERROR_NOT_AVAILABLE; 4903 #endif 4904 } 4905 4906 NS_IMETHODIMP 4907 nsDOMWindowUtils::RestoreHiDPIMode() { 4908 #ifdef DEBUG 4909 nsCOMPtr<nsIWidget> widget = GetWidget(); 4910 if (!widget) return NS_ERROR_FAILURE; 4911 4912 return widget->RestoreHiDPIMode(); 4913 #else 4914 return NS_ERROR_NOT_AVAILABLE; 4915 #endif 4916 } 4917 4918 NS_IMETHODIMP 4919 nsDOMWindowUtils::GetDragSession(nsIDragSession** aSession) { 4920 RefPtr<nsIDragSession> session = nsContentUtils::GetDragSession(GetWidget()); 4921 session.forget(aSession); 4922 return NS_OK; 4923 } 4924 4925 NS_IMETHODIMP 4926 nsDOMWindowUtils::SendMozMouseHitTestEvent(float aX, float aY, 4927 Element* aElement) { 4928 RefPtr<PresShell> presShell = GetPresShell(); 4929 nsPoint offset; 4930 RefPtr<nsIWidget> widget = GetWidgetForElement(aElement, &offset); 4931 LayoutDeviceIntPoint refPoint = nsContentUtils::ToWidgetPoint( 4932 CSSPoint(aX, aY), offset, presShell->GetPresContext()); 4933 4934 SynthesizeMouseEventOptions options; 4935 options.mIgnoreRootScrollFrame = true; 4936 options.mIsDOMEventSynthesized = true; 4937 options.mIsWidgetEventSynthesized = true; 4938 options.mIsAsyncEnabled = false; 4939 4940 auto result = nsContentUtils::SynthesizeMouseEvent( 4941 presShell, widget, u"MozMouseHittest"_ns, refPoint, 4942 SynthesizeMouseEventData{}, options, 4943 Optional<OwningNonNull<VoidFunction>>{}); 4944 return result.isOk() ? NS_OK : result.unwrapErr(); 4945 } 4946 4947 NS_IMETHODIMP 4948 nsDOMWindowUtils::GetMicroTaskLevel(uint32_t* aLevel) { 4949 CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); 4950 NS_ENSURE_STATE(ccjs); 4951 *aLevel = ccjs->MicroTaskLevel(); 4952 return NS_OK; 4953 } 4954 4955 NS_IMETHODIMP 4956 nsDOMWindowUtils::SetMicroTaskLevel(uint32_t aLevel) { 4957 CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get(); 4958 NS_ENSURE_STATE(ccjs); 4959 ccjs->SetMicroTaskLevel(aLevel); 4960 return NS_OK; 4961 }