1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/nsPresShell.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,10352 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: set ts=2 sw=2 et tw=78: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.9 + * 1.10 + * This Original Code has been modified by IBM Corporation. 1.11 + * Modifications made by IBM described herein are 1.12 + * Copyright (c) International Business Machines 1.13 + * Corporation, 2000 1.14 + * 1.15 + * Modifications to Mozilla code or documentation 1.16 + * identified per MPL Section 3.3 1.17 + * 1.18 + * Date Modified by Description of modification 1.19 + * 05/03/2000 IBM Corp. Observer events for reflow states 1.20 + */ 1.21 + 1.22 +/* a presentation of a document, part 2 */ 1.23 + 1.24 +#ifdef MOZ_LOGGING 1.25 +#define FORCE_PR_LOG /* Allow logging in the release build */ 1.26 +#endif 1.27 +#include "prlog.h" 1.28 + 1.29 +#include "mozilla/ArrayUtils.h" 1.30 +#include "mozilla/EventDispatcher.h" 1.31 +#include "mozilla/EventStateManager.h" 1.32 +#include "mozilla/EventStates.h" 1.33 +#include "mozilla/IMEStateManager.h" 1.34 +#include "mozilla/MemoryReporting.h" 1.35 +#include "mozilla/dom/TabChild.h" 1.36 +#include "mozilla/Likely.h" 1.37 +#include "mozilla/MouseEvents.h" 1.38 +#include "mozilla/TextEvents.h" 1.39 +#include "mozilla/TouchEvents.h" 1.40 +#include <algorithm> 1.41 + 1.42 +#ifdef XP_WIN 1.43 +#include "winuser.h" 1.44 +#endif 1.45 + 1.46 +#include "nsPresShell.h" 1.47 +#include "nsPresContext.h" 1.48 +#include "nsIContent.h" 1.49 +#include "mozilla/dom/Element.h" 1.50 +#include "mozilla/dom/Event.h" // for Event::GetEventPopupControlState() 1.51 +#include "mozilla/dom/ShadowRoot.h" 1.52 +#include "mozilla/dom/PointerEvent.h" 1.53 +#include "nsIDocument.h" 1.54 +#include "nsCSSStyleSheet.h" 1.55 +#include "nsAnimationManager.h" 1.56 +#include "nsNameSpaceManager.h" // for Pref-related rule management (bugs 22963,20760,31816) 1.57 +#include "nsFrame.h" 1.58 +#include "FrameLayerBuilder.h" 1.59 +#include "nsViewManager.h" 1.60 +#include "nsView.h" 1.61 +#include "nsCRTGlue.h" 1.62 +#include "prprf.h" 1.63 +#include "prinrval.h" 1.64 +#include "nsTArray.h" 1.65 +#include "nsCOMArray.h" 1.66 +#include "nsContainerFrame.h" 1.67 +#include "nsISelection.h" 1.68 +#include "mozilla/dom/Selection.h" 1.69 +#include "nsGkAtoms.h" 1.70 +#include "nsIDOMRange.h" 1.71 +#include "nsIDOMDocument.h" 1.72 +#include "nsIDOMNode.h" 1.73 +#include "nsIDOMNodeList.h" 1.74 +#include "nsIDOMElement.h" 1.75 +#include "nsRange.h" 1.76 +#include "nsCOMPtr.h" 1.77 +#include "nsAutoPtr.h" 1.78 +#include "nsReadableUtils.h" 1.79 +#include "nsIPageSequenceFrame.h" 1.80 +#include "nsCaret.h" 1.81 +#include "nsIDOMHTMLDocument.h" 1.82 +#include "nsFrameManager.h" 1.83 +#include "nsXPCOM.h" 1.84 +#include "nsILayoutHistoryState.h" 1.85 +#include "nsILineIterator.h" // for ScrollContentIntoView 1.86 +#include "pldhash.h" 1.87 +#include "mozilla/dom/Touch.h" 1.88 +#include "mozilla/dom/PointerEventBinding.h" 1.89 +#include "nsIObserverService.h" 1.90 +#include "nsDocShell.h" // for reflow observation 1.91 +#include "nsIBaseWindow.h" 1.92 +#include "nsError.h" 1.93 +#include "nsLayoutUtils.h" 1.94 +#include "nsViewportInfo.h" 1.95 +#include "nsCSSRendering.h" 1.96 + // for |#ifdef DEBUG| code 1.97 +#include "prenv.h" 1.98 +#include "nsDisplayList.h" 1.99 +#include "nsRegion.h" 1.100 +#include "nsRenderingContext.h" 1.101 +#include "nsAutoLayoutPhase.h" 1.102 +#ifdef MOZ_REFLOW_PERF 1.103 +#include "nsFontMetrics.h" 1.104 +#endif 1.105 +#include "PositionedEventTargeting.h" 1.106 + 1.107 +#include "nsIReflowCallback.h" 1.108 + 1.109 +#include "nsPIDOMWindow.h" 1.110 +#include "nsFocusManager.h" 1.111 +#include "nsIObjectFrame.h" 1.112 +#include "nsIObjectLoadingContent.h" 1.113 +#include "nsNetUtil.h" 1.114 +#include "nsThreadUtils.h" 1.115 +#include "nsStyleSheetService.h" 1.116 +#include "gfxImageSurface.h" 1.117 +#include "gfxContext.h" 1.118 +#include "nsSMILAnimationController.h" 1.119 +#include "SVGContentUtils.h" 1.120 +#include "nsSVGEffects.h" 1.121 +#include "SVGFragmentIdentifier.h" 1.122 +#include "nsArenaMemoryStats.h" 1.123 + 1.124 +#include "nsPerformance.h" 1.125 +#include "nsRefreshDriver.h" 1.126 +#include "nsDOMNavigationTiming.h" 1.127 + 1.128 +// Drag & Drop, Clipboard 1.129 +#include "nsIDocShellTreeItem.h" 1.130 +#include "nsIURI.h" 1.131 +#include "nsIScrollableFrame.h" 1.132 +#include "nsITimer.h" 1.133 +#ifdef ACCESSIBILITY 1.134 +#include "nsAccessibilityService.h" 1.135 +#include "mozilla/a11y/DocAccessible.h" 1.136 +#ifdef DEBUG 1.137 +#include "mozilla/a11y/Logging.h" 1.138 +#endif 1.139 +#endif 1.140 + 1.141 +// For style data reconstruction 1.142 +#include "nsStyleChangeList.h" 1.143 +#include "nsCSSFrameConstructor.h" 1.144 +#ifdef MOZ_XUL 1.145 +#include "nsMenuFrame.h" 1.146 +#include "nsTreeBodyFrame.h" 1.147 +#include "nsIBoxObject.h" 1.148 +#include "nsITreeBoxObject.h" 1.149 +#include "nsMenuPopupFrame.h" 1.150 +#include "nsITreeColumns.h" 1.151 +#include "nsIDOMXULMultSelectCntrlEl.h" 1.152 +#include "nsIDOMXULSelectCntrlItemEl.h" 1.153 +#include "nsIDOMXULMenuListElement.h" 1.154 + 1.155 +#endif 1.156 + 1.157 +#include "GeckoProfiler.h" 1.158 +#include "gfxPlatform.h" 1.159 +#include "Layers.h" 1.160 +#include "LayerTreeInvalidation.h" 1.161 +#include "mozilla/css/ImageLoader.h" 1.162 +#include "mozilla/Preferences.h" 1.163 +#include "mozilla/Telemetry.h" 1.164 +#include "nsCanvasFrame.h" 1.165 +#include "nsIImageLoadingContent.h" 1.166 +#include "nsIScreen.h" 1.167 +#include "nsIScreenManager.h" 1.168 +#include "nsPlaceholderFrame.h" 1.169 +#include "nsTransitionManager.h" 1.170 +#include "ChildIterator.h" 1.171 +#include "RestyleManager.h" 1.172 +#include "nsIDOMHTMLElement.h" 1.173 +#include "nsIDragSession.h" 1.174 +#include "nsIFrameInlines.h" 1.175 +#include "mozilla/gfx/2D.h" 1.176 + 1.177 +#ifdef ANDROID 1.178 +#include "nsIDocShellTreeOwner.h" 1.179 +#endif 1.180 + 1.181 +#ifdef MOZ_TASK_TRACER 1.182 +#include "GeckoTaskTracer.h" 1.183 +using namespace mozilla::tasktracer; 1.184 +#endif 1.185 + 1.186 +#define ANCHOR_SCROLL_FLAGS \ 1.187 + (nsIPresShell::SCROLL_OVERFLOW_HIDDEN | nsIPresShell::SCROLL_NO_PARENT_FRAMES) 1.188 + 1.189 +using namespace mozilla; 1.190 +using namespace mozilla::css; 1.191 +using namespace mozilla::dom; 1.192 +using namespace mozilla::gfx; 1.193 +using namespace mozilla::layers; 1.194 +using namespace mozilla::gfx; 1.195 + 1.196 +CapturingContentInfo nsIPresShell::gCaptureInfo = 1.197 + { false /* mAllowed */, false /* mPointerLock */, false /* mRetargetToElement */, 1.198 + false /* mPreventDrag */, nullptr /* mContent */ }; 1.199 +nsIContent* nsIPresShell::gKeyDownTarget; 1.200 +nsRefPtrHashtable<nsUint32HashKey, dom::Touch>* nsIPresShell::gCaptureTouchList; 1.201 +nsRefPtrHashtable<nsUint32HashKey, nsIContent>* nsIPresShell::gPointerCaptureList; 1.202 +nsClassHashtable<nsUint32HashKey, nsIPresShell::PointerInfo>* nsIPresShell::gActivePointersIds; 1.203 +bool nsIPresShell::gPreventMouseEvents = false; 1.204 + 1.205 +// convert a color value to a string, in the CSS format #RRGGBB 1.206 +// * - initially created for bugs 31816, 20760, 22963 1.207 +static void ColorToString(nscolor aColor, nsAutoString &aString); 1.208 + 1.209 +// RangePaintInfo is used to paint ranges to offscreen buffers 1.210 +struct RangePaintInfo { 1.211 + nsRefPtr<nsRange> mRange; 1.212 + nsDisplayListBuilder mBuilder; 1.213 + nsDisplayList mList; 1.214 + 1.215 + // offset of builder's reference frame to the root frame 1.216 + nsPoint mRootOffset; 1.217 + 1.218 + RangePaintInfo(nsRange* aRange, nsIFrame* aFrame) 1.219 + : mRange(aRange), mBuilder(aFrame, nsDisplayListBuilder::PAINTING, false) 1.220 + { 1.221 + MOZ_COUNT_CTOR(RangePaintInfo); 1.222 + } 1.223 + 1.224 + ~RangePaintInfo() 1.225 + { 1.226 + mList.DeleteAll(); 1.227 + MOZ_COUNT_DTOR(RangePaintInfo); 1.228 + } 1.229 +}; 1.230 + 1.231 +#undef NOISY 1.232 + 1.233 +// ---------------------------------------------------------------------- 1.234 + 1.235 +#ifdef DEBUG 1.236 +// Set the environment variable GECKO_VERIFY_REFLOW_FLAGS to one or 1.237 +// more of the following flags (comma separated) for handy debug 1.238 +// output. 1.239 +static uint32_t gVerifyReflowFlags; 1.240 + 1.241 +struct VerifyReflowFlags { 1.242 + const char* name; 1.243 + uint32_t bit; 1.244 +}; 1.245 + 1.246 +static const VerifyReflowFlags gFlags[] = { 1.247 + { "verify", VERIFY_REFLOW_ON }, 1.248 + { "reflow", VERIFY_REFLOW_NOISY }, 1.249 + { "all", VERIFY_REFLOW_ALL }, 1.250 + { "list-commands", VERIFY_REFLOW_DUMP_COMMANDS }, 1.251 + { "noisy-commands", VERIFY_REFLOW_NOISY_RC }, 1.252 + { "really-noisy-commands", VERIFY_REFLOW_REALLY_NOISY_RC }, 1.253 + { "resize", VERIFY_REFLOW_DURING_RESIZE_REFLOW }, 1.254 +}; 1.255 + 1.256 +#define NUM_VERIFY_REFLOW_FLAGS (sizeof(gFlags) / sizeof(gFlags[0])) 1.257 + 1.258 +static void 1.259 +ShowVerifyReflowFlags() 1.260 +{ 1.261 + printf("Here are the available GECKO_VERIFY_REFLOW_FLAGS:\n"); 1.262 + const VerifyReflowFlags* flag = gFlags; 1.263 + const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS; 1.264 + while (flag < limit) { 1.265 + printf(" %s\n", flag->name); 1.266 + ++flag; 1.267 + } 1.268 + printf("Note: GECKO_VERIFY_REFLOW_FLAGS is a comma separated list of flag\n"); 1.269 + printf("names (no whitespace)\n"); 1.270 +} 1.271 +#endif 1.272 + 1.273 +//======================================================================== 1.274 +//======================================================================== 1.275 +//======================================================================== 1.276 +#ifdef MOZ_REFLOW_PERF 1.277 +class ReflowCountMgr; 1.278 + 1.279 +static const char kGrandTotalsStr[] = "Grand Totals"; 1.280 + 1.281 +// Counting Class 1.282 +class ReflowCounter { 1.283 +public: 1.284 + ReflowCounter(ReflowCountMgr * aMgr = nullptr); 1.285 + ~ReflowCounter(); 1.286 + 1.287 + void ClearTotals(); 1.288 + void DisplayTotals(const char * aStr); 1.289 + void DisplayDiffTotals(const char * aStr); 1.290 + void DisplayHTMLTotals(const char * aStr); 1.291 + 1.292 + void Add() { mTotal++; } 1.293 + void Add(uint32_t aTotal) { mTotal += aTotal; } 1.294 + 1.295 + void CalcDiffInTotals(); 1.296 + void SetTotalsCache(); 1.297 + 1.298 + void SetMgr(ReflowCountMgr * aMgr) { mMgr = aMgr; } 1.299 + 1.300 + uint32_t GetTotal() { return mTotal; } 1.301 + 1.302 +protected: 1.303 + void DisplayTotals(uint32_t aTotal, const char * aTitle); 1.304 + void DisplayHTMLTotals(uint32_t aTotal, const char * aTitle); 1.305 + 1.306 + uint32_t mTotal; 1.307 + uint32_t mCacheTotal; 1.308 + 1.309 + ReflowCountMgr * mMgr; // weak reference (don't delete) 1.310 +}; 1.311 + 1.312 +// Counting Class 1.313 +class IndiReflowCounter { 1.314 +public: 1.315 + IndiReflowCounter(ReflowCountMgr * aMgr = nullptr) 1.316 + : mFrame(nullptr), 1.317 + mCount(0), 1.318 + mMgr(aMgr), 1.319 + mCounter(aMgr), 1.320 + mHasBeenOutput(false) 1.321 + {} 1.322 + virtual ~IndiReflowCounter() {} 1.323 + 1.324 + nsAutoString mName; 1.325 + nsIFrame * mFrame; // weak reference (don't delete) 1.326 + int32_t mCount; 1.327 + 1.328 + ReflowCountMgr * mMgr; // weak reference (don't delete) 1.329 + 1.330 + ReflowCounter mCounter; 1.331 + bool mHasBeenOutput; 1.332 + 1.333 +}; 1.334 + 1.335 +//-------------------- 1.336 +// Manager Class 1.337 +//-------------------- 1.338 +class ReflowCountMgr { 1.339 +public: 1.340 + ReflowCountMgr(); 1.341 + virtual ~ReflowCountMgr(); 1.342 + 1.343 + void ClearTotals(); 1.344 + void ClearGrandTotals(); 1.345 + void DisplayTotals(const char * aStr); 1.346 + void DisplayHTMLTotals(const char * aStr); 1.347 + void DisplayDiffsInTotals(const char * aStr); 1.348 + 1.349 + void Add(const char * aName, nsIFrame * aFrame); 1.350 + ReflowCounter * LookUp(const char * aName); 1.351 + 1.352 + void PaintCount(const char *aName, nsRenderingContext* aRenderingContext, 1.353 + nsPresContext *aPresContext, nsIFrame *aFrame, 1.354 + const nsPoint &aOffset, uint32_t aColor); 1.355 + 1.356 + FILE * GetOutFile() { return mFD; } 1.357 + 1.358 + PLHashTable * GetIndiFrameHT() { return mIndiFrameCounts; } 1.359 + 1.360 + void SetPresContext(nsPresContext * aPresContext) { mPresContext = aPresContext; } // weak reference 1.361 + void SetPresShell(nsIPresShell* aPresShell) { mPresShell= aPresShell; } // weak reference 1.362 + 1.363 + void SetDumpFrameCounts(bool aVal) { mDumpFrameCounts = aVal; } 1.364 + void SetDumpFrameByFrameCounts(bool aVal) { mDumpFrameByFrameCounts = aVal; } 1.365 + void SetPaintFrameCounts(bool aVal) { mPaintFrameByFrameCounts = aVal; } 1.366 + 1.367 + bool IsPaintingFrameCounts() { return mPaintFrameByFrameCounts; } 1.368 + 1.369 +protected: 1.370 + void DisplayTotals(uint32_t aTotal, uint32_t * aDupArray, char * aTitle); 1.371 + void DisplayHTMLTotals(uint32_t aTotal, uint32_t * aDupArray, char * aTitle); 1.372 + 1.373 + static int RemoveItems(PLHashEntry *he, int i, void *arg); 1.374 + static int RemoveIndiItems(PLHashEntry *he, int i, void *arg); 1.375 + void CleanUp(); 1.376 + 1.377 + // stdout Output Methods 1.378 + static int DoSingleTotal(PLHashEntry *he, int i, void *arg); 1.379 + static int DoSingleIndi(PLHashEntry *he, int i, void *arg); 1.380 + 1.381 + void DoGrandTotals(); 1.382 + void DoIndiTotalsTree(); 1.383 + 1.384 + // HTML Output Methods 1.385 + static int DoSingleHTMLTotal(PLHashEntry *he, int i, void *arg); 1.386 + void DoGrandHTMLTotals(); 1.387 + 1.388 + // Zero Out the Totals 1.389 + static int DoClearTotals(PLHashEntry *he, int i, void *arg); 1.390 + 1.391 + // Displays the Diff Totals 1.392 + static int DoDisplayDiffTotals(PLHashEntry *he, int i, void *arg); 1.393 + 1.394 + PLHashTable * mCounts; 1.395 + PLHashTable * mIndiFrameCounts; 1.396 + FILE * mFD; 1.397 + 1.398 + bool mDumpFrameCounts; 1.399 + bool mDumpFrameByFrameCounts; 1.400 + bool mPaintFrameByFrameCounts; 1.401 + 1.402 + bool mCycledOnce; 1.403 + 1.404 + // Root Frame for Individual Tracking 1.405 + nsPresContext * mPresContext; 1.406 + nsIPresShell* mPresShell; 1.407 + 1.408 + // ReflowCountMgr gReflowCountMgr; 1.409 +}; 1.410 +#endif 1.411 +//======================================================================== 1.412 + 1.413 +// comment out to hide caret 1.414 +#define SHOW_CARET 1.415 + 1.416 +// The upper bound on the amount of time to spend reflowing, in 1.417 +// microseconds. When this bound is exceeded and reflow commands are 1.418 +// still queued up, a reflow event is posted. The idea is for reflow 1.419 +// to not hog the processor beyond the time specifed in 1.420 +// gMaxRCProcessingTime. This data member is initialized from the 1.421 +// layout.reflow.timeslice pref. 1.422 +#define NS_MAX_REFLOW_TIME 1000000 1.423 +static int32_t gMaxRCProcessingTime = -1; 1.424 + 1.425 +struct nsCallbackEventRequest 1.426 +{ 1.427 + nsIReflowCallback* callback; 1.428 + nsCallbackEventRequest* next; 1.429 +}; 1.430 + 1.431 +// ---------------------------------------------------------------------------- 1.432 +#define ASSERT_REFLOW_SCHEDULED_STATE() \ 1.433 + NS_ASSERTION(mReflowScheduled == \ 1.434 + GetPresContext()->RefreshDriver()-> \ 1.435 + IsLayoutFlushObserver(this), "Unexpected state") 1.436 + 1.437 +class nsAutoCauseReflowNotifier 1.438 +{ 1.439 +public: 1.440 + nsAutoCauseReflowNotifier(PresShell* aShell) 1.441 + : mShell(aShell) 1.442 + { 1.443 + mShell->WillCauseReflow(); 1.444 + } 1.445 + ~nsAutoCauseReflowNotifier() 1.446 + { 1.447 + // This check should not be needed. Currently the only place that seem 1.448 + // to need it is the code that deals with bug 337586. 1.449 + if (!mShell->mHaveShutDown) { 1.450 + mShell->DidCauseReflow(); 1.451 + } 1.452 + else { 1.453 + nsContentUtils::RemoveScriptBlocker(); 1.454 + } 1.455 + } 1.456 + 1.457 + PresShell* mShell; 1.458 +}; 1.459 + 1.460 +class MOZ_STACK_CLASS nsPresShellEventCB : public EventDispatchingCallback 1.461 +{ 1.462 +public: 1.463 + nsPresShellEventCB(PresShell* aPresShell) : mPresShell(aPresShell) {} 1.464 + 1.465 + virtual void HandleEvent(EventChainPostVisitor& aVisitor) MOZ_OVERRIDE 1.466 + { 1.467 + if (aVisitor.mPresContext && aVisitor.mEvent->eventStructType != NS_EVENT) { 1.468 + if (aVisitor.mEvent->message == NS_MOUSE_BUTTON_DOWN || 1.469 + aVisitor.mEvent->message == NS_MOUSE_BUTTON_UP) { 1.470 + // Mouse-up and mouse-down events call nsFrame::HandlePress/Release 1.471 + // which call GetContentOffsetsFromPoint which requires up-to-date layout. 1.472 + // Bring layout up-to-date now so that GetCurrentEventFrame() below 1.473 + // will return a real frame and we don't have to worry about 1.474 + // destroying it by flushing later. 1.475 + mPresShell->FlushPendingNotifications(Flush_Layout); 1.476 + } else if (aVisitor.mEvent->message == NS_WHEEL_WHEEL && 1.477 + aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) { 1.478 + nsIFrame* frame = mPresShell->GetCurrentEventFrame(); 1.479 + if (frame) { 1.480 + // chrome (including addons) should be able to know if content 1.481 + // handles both D3E "wheel" event and legacy mouse scroll events. 1.482 + // We should dispatch legacy mouse events before dispatching the 1.483 + // "wheel" event into system group. 1.484 + nsRefPtr<EventStateManager> esm = 1.485 + aVisitor.mPresContext->EventStateManager(); 1.486 + esm->DispatchLegacyMouseScrollEvents(frame, 1.487 + aVisitor.mEvent->AsWheelEvent(), 1.488 + &aVisitor.mEventStatus); 1.489 + } 1.490 + } 1.491 + nsIFrame* frame = mPresShell->GetCurrentEventFrame(); 1.492 + if (!frame && 1.493 + (aVisitor.mEvent->message == NS_MOUSE_BUTTON_UP || 1.494 + aVisitor.mEvent->message == NS_TOUCH_END)) { 1.495 + // Redirect BUTTON_UP and TOUCH_END events to the root frame to ensure 1.496 + // that capturing is released. 1.497 + frame = mPresShell->GetRootFrame(); 1.498 + } 1.499 + if (frame) { 1.500 + frame->HandleEvent(aVisitor.mPresContext, 1.501 + aVisitor.mEvent->AsGUIEvent(), 1.502 + &aVisitor.mEventStatus); 1.503 + } 1.504 + } 1.505 + } 1.506 + 1.507 + nsRefPtr<PresShell> mPresShell; 1.508 +}; 1.509 + 1.510 +class nsBeforeFirstPaintDispatcher : public nsRunnable 1.511 +{ 1.512 +public: 1.513 + nsBeforeFirstPaintDispatcher(nsIDocument* aDocument) 1.514 + : mDocument(aDocument) {} 1.515 + 1.516 + // Fires the "before-first-paint" event so that interested parties (right now, the 1.517 + // mobile browser) are aware of it. 1.518 + NS_IMETHOD Run() MOZ_OVERRIDE 1.519 + { 1.520 + nsCOMPtr<nsIObserverService> observerService = 1.521 + mozilla::services::GetObserverService(); 1.522 + if (observerService) { 1.523 + observerService->NotifyObservers(mDocument, "before-first-paint", 1.524 + nullptr); 1.525 + } 1.526 + return NS_OK; 1.527 + } 1.528 + 1.529 +private: 1.530 + nsCOMPtr<nsIDocument> mDocument; 1.531 +}; 1.532 + 1.533 +bool PresShell::sDisableNonTestMouseEvents = false; 1.534 + 1.535 +#ifdef PR_LOGGING 1.536 +PRLogModuleInfo* PresShell::gLog; 1.537 +#endif 1.538 + 1.539 +#ifdef DEBUG 1.540 +static void 1.541 +VerifyStyleTree(nsPresContext* aPresContext, nsFrameManager* aFrameManager) 1.542 +{ 1.543 + if (nsFrame::GetVerifyStyleTreeEnable()) { 1.544 + nsIFrame* rootFrame = aFrameManager->GetRootFrame(); 1.545 + aPresContext->RestyleManager()->DebugVerifyStyleTree(rootFrame); 1.546 + } 1.547 +} 1.548 +#define VERIFY_STYLE_TREE ::VerifyStyleTree(mPresContext, mFrameConstructor) 1.549 +#else 1.550 +#define VERIFY_STYLE_TREE 1.551 +#endif 1.552 + 1.553 +static bool gVerifyReflowEnabled; 1.554 + 1.555 +bool 1.556 +nsIPresShell::GetVerifyReflowEnable() 1.557 +{ 1.558 +#ifdef DEBUG 1.559 + static bool firstTime = true; 1.560 + if (firstTime) { 1.561 + firstTime = false; 1.562 + char* flags = PR_GetEnv("GECKO_VERIFY_REFLOW_FLAGS"); 1.563 + if (flags) { 1.564 + bool error = false; 1.565 + 1.566 + for (;;) { 1.567 + char* comma = PL_strchr(flags, ','); 1.568 + if (comma) 1.569 + *comma = '\0'; 1.570 + 1.571 + bool found = false; 1.572 + const VerifyReflowFlags* flag = gFlags; 1.573 + const VerifyReflowFlags* limit = gFlags + NUM_VERIFY_REFLOW_FLAGS; 1.574 + while (flag < limit) { 1.575 + if (PL_strcasecmp(flag->name, flags) == 0) { 1.576 + gVerifyReflowFlags |= flag->bit; 1.577 + found = true; 1.578 + break; 1.579 + } 1.580 + ++flag; 1.581 + } 1.582 + 1.583 + if (! found) 1.584 + error = true; 1.585 + 1.586 + if (! comma) 1.587 + break; 1.588 + 1.589 + *comma = ','; 1.590 + flags = comma + 1; 1.591 + } 1.592 + 1.593 + if (error) 1.594 + ShowVerifyReflowFlags(); 1.595 + } 1.596 + 1.597 + if (VERIFY_REFLOW_ON & gVerifyReflowFlags) { 1.598 + gVerifyReflowEnabled = true; 1.599 + 1.600 + printf("Note: verifyreflow is enabled"); 1.601 + if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) { 1.602 + printf(" (noisy)"); 1.603 + } 1.604 + if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) { 1.605 + printf(" (all)"); 1.606 + } 1.607 + if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) { 1.608 + printf(" (show reflow commands)"); 1.609 + } 1.610 + if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { 1.611 + printf(" (noisy reflow commands)"); 1.612 + if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) { 1.613 + printf(" (REALLY noisy reflow commands)"); 1.614 + } 1.615 + } 1.616 + printf("\n"); 1.617 + } 1.618 + } 1.619 +#endif 1.620 + return gVerifyReflowEnabled; 1.621 +} 1.622 + 1.623 +void 1.624 +PresShell::AddInvalidateHiddenPresShellObserver(nsRefreshDriver *aDriver) 1.625 +{ 1.626 + if (!mHiddenInvalidationObserverRefreshDriver && !mIsDestroying && !mHaveShutDown) { 1.627 + aDriver->AddPresShellToInvalidateIfHidden(this); 1.628 + mHiddenInvalidationObserverRefreshDriver = aDriver; 1.629 + } 1.630 +} 1.631 + 1.632 +void 1.633 +nsIPresShell::InvalidatePresShellIfHidden() 1.634 +{ 1.635 + if (!IsVisible() && mPresContext) { 1.636 + mPresContext->NotifyInvalidation(0); 1.637 + } 1.638 + mHiddenInvalidationObserverRefreshDriver = nullptr; 1.639 +} 1.640 + 1.641 +void 1.642 +nsIPresShell::CancelInvalidatePresShellIfHidden() 1.643 +{ 1.644 + if (mHiddenInvalidationObserverRefreshDriver) { 1.645 + mHiddenInvalidationObserverRefreshDriver->RemovePresShellToInvalidateIfHidden(this); 1.646 + mHiddenInvalidationObserverRefreshDriver = nullptr; 1.647 + } 1.648 +} 1.649 + 1.650 +void 1.651 +nsIPresShell::SetVerifyReflowEnable(bool aEnabled) 1.652 +{ 1.653 + gVerifyReflowEnabled = aEnabled; 1.654 +} 1.655 + 1.656 +/* virtual */ void 1.657 +nsIPresShell::AddWeakFrameExternal(nsWeakFrame* aWeakFrame) 1.658 +{ 1.659 + AddWeakFrameInternal(aWeakFrame); 1.660 +} 1.661 + 1.662 +void 1.663 +nsIPresShell::AddWeakFrameInternal(nsWeakFrame* aWeakFrame) 1.664 +{ 1.665 + if (aWeakFrame->GetFrame()) { 1.666 + aWeakFrame->GetFrame()->AddStateBits(NS_FRAME_EXTERNAL_REFERENCE); 1.667 + } 1.668 + aWeakFrame->SetPreviousWeakFrame(mWeakFrames); 1.669 + mWeakFrames = aWeakFrame; 1.670 +} 1.671 + 1.672 +/* virtual */ void 1.673 +nsIPresShell::RemoveWeakFrameExternal(nsWeakFrame* aWeakFrame) 1.674 +{ 1.675 + RemoveWeakFrameInternal(aWeakFrame); 1.676 +} 1.677 + 1.678 +void 1.679 +nsIPresShell::RemoveWeakFrameInternal(nsWeakFrame* aWeakFrame) 1.680 +{ 1.681 + if (mWeakFrames == aWeakFrame) { 1.682 + mWeakFrames = aWeakFrame->GetPreviousWeakFrame(); 1.683 + return; 1.684 + } 1.685 + nsWeakFrame* nextWeak = mWeakFrames; 1.686 + while (nextWeak && nextWeak->GetPreviousWeakFrame() != aWeakFrame) { 1.687 + nextWeak = nextWeak->GetPreviousWeakFrame(); 1.688 + } 1.689 + if (nextWeak) { 1.690 + nextWeak->SetPreviousWeakFrame(aWeakFrame->GetPreviousWeakFrame()); 1.691 + } 1.692 +} 1.693 + 1.694 +already_AddRefed<nsFrameSelection> 1.695 +nsIPresShell::FrameSelection() 1.696 +{ 1.697 + nsRefPtr<nsFrameSelection> ret = mSelection; 1.698 + return ret.forget(); 1.699 +} 1.700 + 1.701 +//---------------------------------------------------------------------- 1.702 + 1.703 +static bool sSynthMouseMove = true; 1.704 +static uint32_t sNextPresShellId; 1.705 +static bool sPointerEventEnabled = true; 1.706 + 1.707 +PresShell::PresShell() 1.708 + : mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) 1.709 +{ 1.710 + mSelection = nullptr; 1.711 +#ifdef MOZ_REFLOW_PERF 1.712 + mReflowCountMgr = new ReflowCountMgr(); 1.713 + mReflowCountMgr->SetPresContext(mPresContext); 1.714 + mReflowCountMgr->SetPresShell(this); 1.715 +#endif 1.716 +#ifdef PR_LOGGING 1.717 + mLoadBegin = TimeStamp::Now(); 1.718 + if (!gLog) { 1.719 + gLog = PR_NewLogModule("PresShell"); 1.720 + } 1.721 +#endif 1.722 + mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES; 1.723 + mIsThemeSupportDisabled = false; 1.724 + mIsActive = true; 1.725 + // FIXME/bug 735029: find a better solution to this problem 1.726 +#ifdef MOZ_ANDROID_OMTC 1.727 + // The java pan/zoom code uses this to mean approximately "request a 1.728 + // reset of pan/zoom state" which doesn't necessarily correspond 1.729 + // with the first paint of content. 1.730 + mIsFirstPaint = false; 1.731 +#else 1.732 + mIsFirstPaint = true; 1.733 +#endif 1.734 + mPresShellId = sNextPresShellId++; 1.735 + mFrozen = false; 1.736 +#ifdef DEBUG 1.737 + mPresArenaAllocCount = 0; 1.738 +#endif 1.739 + mRenderFlags = 0; 1.740 + mXResolution = 1.0; 1.741 + mYResolution = 1.0; 1.742 + mViewportOverridden = false; 1.743 + 1.744 + mScrollPositionClampingScrollPortSizeSet = false; 1.745 + 1.746 + mMaxLineBoxWidth = 0; 1.747 + 1.748 + static bool addedSynthMouseMove = false; 1.749 + if (!addedSynthMouseMove) { 1.750 + Preferences::AddBoolVarCache(&sSynthMouseMove, 1.751 + "layout.reflow.synthMouseMove", true); 1.752 + addedSynthMouseMove = true; 1.753 + } 1.754 + static bool addedPointerEventEnabled = false; 1.755 + if (!addedPointerEventEnabled) { 1.756 + Preferences::AddBoolVarCache(&sPointerEventEnabled, 1.757 + "dom.w3c_pointer_events.enabled", true); 1.758 + addedPointerEventEnabled = true; 1.759 + } 1.760 + 1.761 + mPaintingIsFrozen = false; 1.762 +} 1.763 + 1.764 +NS_IMPL_ISUPPORTS(PresShell, nsIPresShell, nsIDocumentObserver, 1.765 + nsISelectionController, 1.766 + nsISelectionDisplay, nsIObserver, nsISupportsWeakReference, 1.767 + nsIMutationObserver) 1.768 + 1.769 +PresShell::~PresShell() 1.770 +{ 1.771 + if (!mHaveShutDown) { 1.772 + NS_NOTREACHED("Someone did not call nsIPresShell::destroy"); 1.773 + Destroy(); 1.774 + } 1.775 + 1.776 + NS_ASSERTION(mCurrentEventContentStack.Count() == 0, 1.777 + "Huh, event content left on the stack in pres shell dtor!"); 1.778 + NS_ASSERTION(mFirstCallbackEventRequest == nullptr && 1.779 + mLastCallbackEventRequest == nullptr, 1.780 + "post-reflow queues not empty. This means we're leaking"); 1.781 + 1.782 + // Verify that if painting was frozen, but we're being removed from the tree, 1.783 + // that we now re-enable painting on our refresh driver, since it may need to 1.784 + // be re-used by another presentation. 1.785 + if (mPaintingIsFrozen) { 1.786 + mPresContext->RefreshDriver()->Thaw(); 1.787 + } 1.788 + 1.789 +#ifdef DEBUG 1.790 + MOZ_ASSERT(mPresArenaAllocCount == 0, 1.791 + "Some pres arena objects were not freed"); 1.792 +#endif 1.793 + 1.794 + delete mStyleSet; 1.795 + delete mFrameConstructor; 1.796 + 1.797 + mCurrentEventContent = nullptr; 1.798 + 1.799 + NS_IF_RELEASE(mPresContext); 1.800 + NS_IF_RELEASE(mDocument); 1.801 + NS_IF_RELEASE(mSelection); 1.802 +} 1.803 + 1.804 +/** 1.805 + * Initialize the presentation shell. Create view manager and style 1.806 + * manager. 1.807 + * Note this can't be merged into our constructor because caret initialization 1.808 + * calls AddRef() on us. 1.809 + */ 1.810 +void 1.811 +PresShell::Init(nsIDocument* aDocument, 1.812 + nsPresContext* aPresContext, 1.813 + nsViewManager* aViewManager, 1.814 + nsStyleSet* aStyleSet, 1.815 + nsCompatibility aCompatMode) 1.816 +{ 1.817 + NS_PRECONDITION(aDocument, "null ptr"); 1.818 + NS_PRECONDITION(aPresContext, "null ptr"); 1.819 + NS_PRECONDITION(aViewManager, "null ptr"); 1.820 + NS_PRECONDITION(!mDocument, "already initialized"); 1.821 + 1.822 + if (!aDocument || !aPresContext || !aViewManager || mDocument) { 1.823 + return; 1.824 + } 1.825 + 1.826 + mDocument = aDocument; 1.827 + NS_ADDREF(mDocument); 1.828 + mViewManager = aViewManager; 1.829 + 1.830 + // Create our frame constructor. 1.831 + mFrameConstructor = new nsCSSFrameConstructor(mDocument, this, aStyleSet); 1.832 + 1.833 + mFrameManager = mFrameConstructor; 1.834 + 1.835 + // The document viewer owns both view manager and pres shell. 1.836 + mViewManager->SetPresShell(this); 1.837 + 1.838 + // Bind the context to the presentation shell. 1.839 + mPresContext = aPresContext; 1.840 + NS_ADDREF(mPresContext); 1.841 + aPresContext->SetShell(this); 1.842 + 1.843 + // Now we can initialize the style set. 1.844 + aStyleSet->Init(aPresContext); 1.845 + mStyleSet = aStyleSet; 1.846 + 1.847 + // Notify our prescontext that it now has a compatibility mode. Note that 1.848 + // this MUST happen after we set up our style set but before we create any 1.849 + // frames. 1.850 + mPresContext->CompatibilityModeChanged(); 1.851 + 1.852 + // setup the preference style rules (no forced reflow), and do it 1.853 + // before creating any frames. 1.854 + SetPreferenceStyleRules(false); 1.855 + 1.856 + NS_ADDREF(mSelection = new nsFrameSelection()); 1.857 + 1.858 + mSelection->Init(this, nullptr); 1.859 + 1.860 + // Important: this has to happen after the selection has been set up 1.861 +#ifdef SHOW_CARET 1.862 + // make the caret 1.863 + mCaret = new nsCaret(); 1.864 + mCaret->Init(this); 1.865 + mOriginalCaret = mCaret; 1.866 + 1.867 + //SetCaretEnabled(true); // make it show in browser windows 1.868 +#endif 1.869 + //set up selection to be displayed in document 1.870 + // Don't enable selection for print media 1.871 + nsPresContext::nsPresContextType type = aPresContext->Type(); 1.872 + if (type != nsPresContext::eContext_PrintPreview && 1.873 + type != nsPresContext::eContext_Print) 1.874 + SetDisplaySelection(nsISelectionController::SELECTION_DISABLED); 1.875 + 1.876 + if (gMaxRCProcessingTime == -1) { 1.877 + gMaxRCProcessingTime = 1.878 + Preferences::GetInt("layout.reflow.timeslice", NS_MAX_REFLOW_TIME); 1.879 + } 1.880 + 1.881 + { 1.882 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.883 + if (os) { 1.884 + os->AddObserver(this, "agent-sheet-added", false); 1.885 + os->AddObserver(this, "user-sheet-added", false); 1.886 + os->AddObserver(this, "author-sheet-added", false); 1.887 + os->AddObserver(this, "agent-sheet-removed", false); 1.888 + os->AddObserver(this, "user-sheet-removed", false); 1.889 + os->AddObserver(this, "author-sheet-removed", false); 1.890 +#ifdef MOZ_XUL 1.891 + os->AddObserver(this, "chrome-flush-skin-caches", false); 1.892 +#endif 1.893 + } 1.894 + } 1.895 + 1.896 +#ifdef MOZ_REFLOW_PERF 1.897 + if (mReflowCountMgr) { 1.898 + bool paintFrameCounts = 1.899 + Preferences::GetBool("layout.reflow.showframecounts"); 1.900 + 1.901 + bool dumpFrameCounts = 1.902 + Preferences::GetBool("layout.reflow.dumpframecounts"); 1.903 + 1.904 + bool dumpFrameByFrameCounts = 1.905 + Preferences::GetBool("layout.reflow.dumpframebyframecounts"); 1.906 + 1.907 + mReflowCountMgr->SetDumpFrameCounts(dumpFrameCounts); 1.908 + mReflowCountMgr->SetDumpFrameByFrameCounts(dumpFrameByFrameCounts); 1.909 + mReflowCountMgr->SetPaintFrameCounts(paintFrameCounts); 1.910 + } 1.911 +#endif 1.912 + 1.913 + if (mDocument->HasAnimationController()) { 1.914 + nsSMILAnimationController* animCtrl = mDocument->GetAnimationController(); 1.915 + animCtrl->NotifyRefreshDriverCreated(GetPresContext()->RefreshDriver()); 1.916 + } 1.917 + 1.918 + // Get our activeness from the docShell. 1.919 + QueryIsActive(); 1.920 + 1.921 + // Setup our font inflation preferences. 1.922 + SetupFontInflation(); 1.923 +} 1.924 + 1.925 +#ifdef PR_LOGGING 1.926 +enum TextPerfLogType { 1.927 + eLog_reflow, 1.928 + eLog_loaddone, 1.929 + eLog_totals 1.930 +}; 1.931 + 1.932 +static void 1.933 +LogTextPerfStats(gfxTextPerfMetrics* aTextPerf, 1.934 + PresShell* aPresShell, 1.935 + const gfxTextPerfMetrics::TextCounts& aCounts, 1.936 + float aTime, TextPerfLogType aLogType, const char* aURL) 1.937 +{ 1.938 + char prefix[256]; 1.939 + 1.940 + switch (aLogType) { 1.941 + case eLog_reflow: 1.942 + sprintf(prefix, "(textperf-reflow) %p time-ms: %7.0f", aPresShell, aTime); 1.943 + break; 1.944 + case eLog_loaddone: 1.945 + sprintf(prefix, "(textperf-loaddone) %p time-ms: %7.0f", aPresShell, aTime); 1.946 + break; 1.947 + default: 1.948 + MOZ_ASSERT(aLogType == eLog_totals, "unknown textperf log type"); 1.949 + sprintf(prefix, "(textperf-totals) %p", aPresShell); 1.950 + } 1.951 + 1.952 + PRLogModuleInfo* tpLog = gfxPlatform::GetLog(eGfxLog_textperf); 1.953 + 1.954 + // ignore XUL contexts unless at debug level 1.955 + PRLogModuleLevel logLevel = PR_LOG_WARNING; 1.956 + if (aCounts.numContentTextRuns == 0) { 1.957 + logLevel = PR_LOG_DEBUG; 1.958 + } 1.959 + 1.960 + double hitRatio = 0.0; 1.961 + uint32_t lookups = aCounts.wordCacheHit + aCounts.wordCacheMiss; 1.962 + if (lookups) { 1.963 + hitRatio = double(aCounts.wordCacheHit) / double(lookups); 1.964 + } 1.965 + 1.966 + if (aLogType == eLog_loaddone) { 1.967 + PR_LOG(tpLog, logLevel, 1.968 + ("%s reflow: %d chars: %d " 1.969 + "[%s] " 1.970 + "content-textruns: %d chrome-textruns: %d " 1.971 + "max-textrun-len: %d " 1.972 + "word-cache-lookups: %d word-cache-hit-ratio: %4.3f " 1.973 + "word-cache-space: %d word-cache-long: %d " 1.974 + "pref-fallbacks: %d system-fallbacks: %d " 1.975 + "textruns-const: %d textruns-destr: %d " 1.976 + "cumulative-textruns-destr: %d\n", 1.977 + prefix, aTextPerf->reflowCount, aCounts.numChars, 1.978 + (aURL ? aURL : ""), 1.979 + aCounts.numContentTextRuns, aCounts.numChromeTextRuns, 1.980 + aCounts.maxTextRunLen, 1.981 + lookups, hitRatio, 1.982 + aCounts.wordCacheSpaceRules, aCounts.wordCacheLong, 1.983 + aCounts.fallbackPrefs, aCounts.fallbackSystem, 1.984 + aCounts.textrunConst, aCounts.textrunDestr, 1.985 + aTextPerf->cumulative.textrunDestr)); 1.986 + } else { 1.987 + PR_LOG(tpLog, logLevel, 1.988 + ("%s reflow: %d chars: %d " 1.989 + "content-textruns: %d chrome-textruns: %d " 1.990 + "max-textrun-len: %d " 1.991 + "word-cache-lookups: %d word-cache-hit-ratio: %4.3f " 1.992 + "word-cache-space: %d word-cache-long: %d " 1.993 + "pref-fallbacks: %d system-fallbacks: %d " 1.994 + "textruns-const: %d textruns-destr: %d " 1.995 + "cumulative-textruns-destr: %d\n", 1.996 + prefix, aTextPerf->reflowCount, aCounts.numChars, 1.997 + aCounts.numContentTextRuns, aCounts.numChromeTextRuns, 1.998 + aCounts.maxTextRunLen, 1.999 + lookups, hitRatio, 1.1000 + aCounts.wordCacheSpaceRules, aCounts.wordCacheLong, 1.1001 + aCounts.fallbackPrefs, aCounts.fallbackSystem, 1.1002 + aCounts.textrunConst, aCounts.textrunDestr, 1.1003 + aTextPerf->cumulative.textrunDestr)); 1.1004 + } 1.1005 +} 1.1006 +#endif 1.1007 + 1.1008 +void 1.1009 +PresShell::Destroy() 1.1010 +{ 1.1011 + NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), 1.1012 + "destroy called on presshell while scripts not blocked"); 1.1013 + 1.1014 + // dump out cumulative text perf metrics 1.1015 +#ifdef PR_LOGGING 1.1016 + gfxTextPerfMetrics* tp; 1.1017 + if (mPresContext && (tp = mPresContext->GetTextPerfMetrics())) { 1.1018 + tp->Accumulate(); 1.1019 + if (tp->cumulative.numChars > 0) { 1.1020 + LogTextPerfStats(tp, this, tp->cumulative, 0.0, eLog_totals, nullptr); 1.1021 + } 1.1022 + } 1.1023 +#endif 1.1024 + 1.1025 +#ifdef MOZ_REFLOW_PERF 1.1026 + DumpReflows(); 1.1027 + if (mReflowCountMgr) { 1.1028 + delete mReflowCountMgr; 1.1029 + mReflowCountMgr = nullptr; 1.1030 + } 1.1031 +#endif 1.1032 + 1.1033 + if (mHaveShutDown) 1.1034 + return; 1.1035 + 1.1036 +#ifdef ACCESSIBILITY 1.1037 + if (mDocAccessible) { 1.1038 +#ifdef DEBUG 1.1039 + if (a11y::logging::IsEnabled(a11y::logging::eDocDestroy)) 1.1040 + a11y::logging::DocDestroy("presshell destroyed", mDocument); 1.1041 +#endif 1.1042 + 1.1043 + mDocAccessible->Shutdown(); 1.1044 + mDocAccessible = nullptr; 1.1045 + } 1.1046 +#endif // ACCESSIBILITY 1.1047 + 1.1048 + MaybeReleaseCapturingContent(); 1.1049 + 1.1050 + if (gKeyDownTarget && gKeyDownTarget->OwnerDoc() == mDocument) { 1.1051 + NS_RELEASE(gKeyDownTarget); 1.1052 + } 1.1053 + 1.1054 + if (mContentToScrollTo) { 1.1055 + mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling); 1.1056 + mContentToScrollTo = nullptr; 1.1057 + } 1.1058 + 1.1059 + if (mPresContext) { 1.1060 + // We need to notify the destroying the nsPresContext to ESM for 1.1061 + // suppressing to use from ESM. 1.1062 + mPresContext->EventStateManager()->NotifyDestroyPresContext(mPresContext); 1.1063 + } 1.1064 + 1.1065 + { 1.1066 + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); 1.1067 + if (os) { 1.1068 + os->RemoveObserver(this, "agent-sheet-added"); 1.1069 + os->RemoveObserver(this, "user-sheet-added"); 1.1070 + os->RemoveObserver(this, "author-sheet-added"); 1.1071 + os->RemoveObserver(this, "agent-sheet-removed"); 1.1072 + os->RemoveObserver(this, "user-sheet-removed"); 1.1073 + os->RemoveObserver(this, "author-sheet-removed"); 1.1074 +#ifdef MOZ_XUL 1.1075 + os->RemoveObserver(this, "chrome-flush-skin-caches"); 1.1076 +#endif 1.1077 + } 1.1078 + } 1.1079 + 1.1080 + // If our paint suppression timer is still active, kill it. 1.1081 + if (mPaintSuppressionTimer) { 1.1082 + mPaintSuppressionTimer->Cancel(); 1.1083 + mPaintSuppressionTimer = nullptr; 1.1084 + } 1.1085 + 1.1086 + // Same for our reflow continuation timer 1.1087 + if (mReflowContinueTimer) { 1.1088 + mReflowContinueTimer->Cancel(); 1.1089 + mReflowContinueTimer = nullptr; 1.1090 + } 1.1091 + 1.1092 + if (mDelayedPaintTimer) { 1.1093 + mDelayedPaintTimer->Cancel(); 1.1094 + mDelayedPaintTimer = nullptr; 1.1095 + } 1.1096 + 1.1097 + mSynthMouseMoveEvent.Revoke(); 1.1098 + 1.1099 + mUpdateImageVisibilityEvent.Revoke(); 1.1100 + 1.1101 + ClearVisibleImagesList(); 1.1102 + 1.1103 + if (mCaret) { 1.1104 + mCaret->Terminate(); 1.1105 + mCaret = nullptr; 1.1106 + } 1.1107 + 1.1108 + if (mSelection) { 1.1109 + mSelection->DisconnectFromPresShell(); 1.1110 + } 1.1111 + 1.1112 + // release our pref style sheet, if we have one still 1.1113 + ClearPreferenceStyleRules(); 1.1114 + 1.1115 + mIsDestroying = true; 1.1116 + 1.1117 + // We can't release all the event content in 1.1118 + // mCurrentEventContentStack here since there might be code on the 1.1119 + // stack that will release the event content too. Double release 1.1120 + // bad! 1.1121 + 1.1122 + // The frames will be torn down, so remove them from the current 1.1123 + // event frame stack (since they'd be dangling references if we'd 1.1124 + // leave them in) and null out the mCurrentEventFrame pointer as 1.1125 + // well. 1.1126 + 1.1127 + mCurrentEventFrame = nullptr; 1.1128 + 1.1129 + int32_t i, count = mCurrentEventFrameStack.Length(); 1.1130 + for (i = 0; i < count; i++) { 1.1131 + mCurrentEventFrameStack[i] = nullptr; 1.1132 + } 1.1133 + 1.1134 + mFramesToDirty.Clear(); 1.1135 + 1.1136 + if (mViewManager) { 1.1137 + // Clear the view manager's weak pointer back to |this| in case it 1.1138 + // was leaked. 1.1139 + mViewManager->SetPresShell(nullptr); 1.1140 + mViewManager = nullptr; 1.1141 + } 1.1142 + 1.1143 + mStyleSet->BeginShutdown(mPresContext); 1.1144 + nsRefreshDriver* rd = GetPresContext()->RefreshDriver(); 1.1145 + 1.1146 + // This shell must be removed from the document before the frame 1.1147 + // hierarchy is torn down to avoid finding deleted frames through 1.1148 + // this presshell while the frames are being torn down 1.1149 + if (mDocument) { 1.1150 + NS_ASSERTION(mDocument->GetShell() == this, "Wrong shell?"); 1.1151 + mDocument->DeleteShell(); 1.1152 + 1.1153 + if (mDocument->HasAnimationController()) { 1.1154 + mDocument->GetAnimationController()->NotifyRefreshDriverDestroying(rd); 1.1155 + } 1.1156 + } 1.1157 + 1.1158 + // Revoke any pending events. We need to do this and cancel pending reflows 1.1159 + // before we destroy the frame manager, since apparently frame destruction 1.1160 + // sometimes spins the event queue when plug-ins are involved(!). 1.1161 + rd->RemoveLayoutFlushObserver(this); 1.1162 + if (mHiddenInvalidationObserverRefreshDriver) { 1.1163 + mHiddenInvalidationObserverRefreshDriver->RemovePresShellToInvalidateIfHidden(this); 1.1164 + } 1.1165 + 1.1166 + if (rd->PresContext() == GetPresContext()) { 1.1167 + rd->RevokeViewManagerFlush(); 1.1168 + } 1.1169 + 1.1170 + mResizeEvent.Revoke(); 1.1171 + if (mAsyncResizeTimerIsActive) { 1.1172 + mAsyncResizeEventTimer->Cancel(); 1.1173 + mAsyncResizeTimerIsActive = false; 1.1174 + } 1.1175 + 1.1176 + CancelAllPendingReflows(); 1.1177 + CancelPostedReflowCallbacks(); 1.1178 + 1.1179 + // Destroy the frame manager. This will destroy the frame hierarchy 1.1180 + mFrameConstructor->WillDestroyFrameTree(); 1.1181 + 1.1182 + // Destroy all frame properties (whose destruction was suppressed 1.1183 + // while destroying the frame tree, but which might contain more 1.1184 + // frames within the properties. 1.1185 + if (mPresContext) { 1.1186 + // Clear out the prescontext's property table -- since our frame tree is 1.1187 + // now dead, we shouldn't be looking up any more properties in that table. 1.1188 + // We want to do this before we call SetShell() on the prescontext, so 1.1189 + // property destructors can usefully call GetPresShell() on the 1.1190 + // prescontext. 1.1191 + mPresContext->PropertyTable()->DeleteAll(); 1.1192 + } 1.1193 + 1.1194 + 1.1195 + NS_WARN_IF_FALSE(!mWeakFrames, "Weak frames alive after destroying FrameManager"); 1.1196 + while (mWeakFrames) { 1.1197 + mWeakFrames->Clear(this); 1.1198 + } 1.1199 + 1.1200 + // Let the style set do its cleanup. 1.1201 + mStyleSet->Shutdown(mPresContext); 1.1202 + 1.1203 + if (mPresContext) { 1.1204 + // We hold a reference to the pres context, and it holds a weak link back 1.1205 + // to us. To avoid the pres context having a dangling reference, set its 1.1206 + // pres shell to nullptr 1.1207 + mPresContext->SetShell(nullptr); 1.1208 + 1.1209 + // Clear the link handler (weak reference) as well 1.1210 + mPresContext->SetLinkHandler(nullptr); 1.1211 + } 1.1212 + 1.1213 + mHaveShutDown = true; 1.1214 + 1.1215 + EvictTouches(); 1.1216 +} 1.1217 + 1.1218 +void 1.1219 +PresShell::MakeZombie() 1.1220 +{ 1.1221 + mIsZombie = true; 1.1222 + CancelAllPendingReflows(); 1.1223 +} 1.1224 + 1.1225 +void 1.1226 +nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled) 1.1227 +{ 1.1228 + if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) { 1.1229 + mStyleSet->SetAuthorStyleDisabled(aStyleDisabled); 1.1230 + ReconstructStyleData(); 1.1231 + 1.1232 + nsCOMPtr<nsIObserverService> observerService = 1.1233 + mozilla::services::GetObserverService(); 1.1234 + if (observerService) { 1.1235 + observerService->NotifyObservers(mDocument, 1.1236 + "author-style-disabled-changed", 1.1237 + nullptr); 1.1238 + } 1.1239 + } 1.1240 +} 1.1241 + 1.1242 +bool 1.1243 +nsIPresShell::GetAuthorStyleDisabled() const 1.1244 +{ 1.1245 + return mStyleSet->GetAuthorStyleDisabled(); 1.1246 +} 1.1247 + 1.1248 +nsresult 1.1249 +PresShell::SetPreferenceStyleRules(bool aForceReflow) 1.1250 +{ 1.1251 + if (!mDocument) { 1.1252 + return NS_ERROR_NULL_POINTER; 1.1253 + } 1.1254 + 1.1255 + nsPIDOMWindow *window = mDocument->GetWindow(); 1.1256 + 1.1257 + // If the document doesn't have a window there's no need to notify 1.1258 + // its presshell about changes to preferences since the document is 1.1259 + // in a state where it doesn't matter any more (see 1.1260 + // nsDocumentViewer::Close()). 1.1261 + 1.1262 + if (!window) { 1.1263 + return NS_ERROR_NULL_POINTER; 1.1264 + } 1.1265 + 1.1266 + NS_PRECONDITION(mPresContext, "presContext cannot be null"); 1.1267 + if (mPresContext) { 1.1268 + // first, make sure this is not a chrome shell 1.1269 + if (nsContentUtils::IsInChromeDocshell(mDocument)) { 1.1270 + return NS_OK; 1.1271 + } 1.1272 + 1.1273 +#ifdef DEBUG_attinasi 1.1274 + printf("Setting Preference Style Rules:\n"); 1.1275 +#endif 1.1276 + // if here, we need to create rules for the prefs 1.1277 + // - this includes the background-color, the text-color, 1.1278 + // the link color, the visited link color and the link-underlining 1.1279 + 1.1280 + // first clear any exising rules 1.1281 + nsresult result = ClearPreferenceStyleRules(); 1.1282 + 1.1283 + // now the link rules (must come after the color rules, or links will not be correct color!) 1.1284 + // XXX - when there is both an override and agent pref stylesheet this won't matter, 1.1285 + // as the color rules will be overrides and the links rules will be agent 1.1286 + if (NS_SUCCEEDED(result)) { 1.1287 + result = SetPrefLinkRules(); 1.1288 + } 1.1289 + if (NS_SUCCEEDED(result)) { 1.1290 + result = SetPrefFocusRules(); 1.1291 + } 1.1292 + if (NS_SUCCEEDED(result)) { 1.1293 + result = SetPrefNoScriptRule(); 1.1294 + } 1.1295 + if (NS_SUCCEEDED(result)) { 1.1296 + result = SetPrefNoFramesRule(); 1.1297 + } 1.1298 +#ifdef DEBUG_attinasi 1.1299 + printf( "Preference Style Rules set: error=%ld\n", (long)result); 1.1300 +#endif 1.1301 + 1.1302 + // Note that this method never needs to force any calculation; the caller 1.1303 + // will recalculate style if needed 1.1304 + 1.1305 + return result; 1.1306 + } 1.1307 + 1.1308 + return NS_ERROR_NULL_POINTER; 1.1309 +} 1.1310 + 1.1311 +nsresult PresShell::ClearPreferenceStyleRules(void) 1.1312 +{ 1.1313 + nsresult result = NS_OK; 1.1314 + if (mPrefStyleSheet) { 1.1315 + NS_ASSERTION(mStyleSet, "null styleset entirely unexpected!"); 1.1316 + if (mStyleSet) { 1.1317 + // remove the sheet from the styleset: 1.1318 + // - note that we have to check for success by comparing the count before and after... 1.1319 +#ifdef DEBUG 1.1320 + int32_t numBefore = mStyleSet->SheetCount(nsStyleSet::eUserSheet); 1.1321 + NS_ASSERTION(numBefore > 0, "no user stylesheets in styleset, but we have one!"); 1.1322 +#endif 1.1323 + mStyleSet->RemoveStyleSheet(nsStyleSet::eUserSheet, mPrefStyleSheet); 1.1324 + 1.1325 +#ifdef DEBUG_attinasi 1.1326 + NS_ASSERTION((numBefore - 1) == mStyleSet->GetNumberOfUserStyleSheets(), 1.1327 + "Pref stylesheet was not removed"); 1.1328 + printf("PrefStyleSheet removed\n"); 1.1329 +#endif 1.1330 + // clear the sheet pointer: it is strictly historical now 1.1331 + mPrefStyleSheet = nullptr; 1.1332 + } 1.1333 + } 1.1334 + return result; 1.1335 +} 1.1336 + 1.1337 +nsresult 1.1338 +PresShell::CreatePreferenceStyleSheet() 1.1339 +{ 1.1340 + NS_ASSERTION(!mPrefStyleSheet, "prefStyleSheet already exists"); 1.1341 + mPrefStyleSheet = new nsCSSStyleSheet(CORS_NONE); 1.1342 + nsCOMPtr<nsIURI> uri; 1.1343 + nsresult rv = NS_NewURI(getter_AddRefs(uri), "about:PreferenceStyleSheet", nullptr); 1.1344 + if (NS_FAILED(rv)) { 1.1345 + mPrefStyleSheet = nullptr; 1.1346 + return rv; 1.1347 + } 1.1348 + NS_ASSERTION(uri, "null but no error"); 1.1349 + mPrefStyleSheet->SetURIs(uri, uri, uri); 1.1350 + mPrefStyleSheet->SetComplete(); 1.1351 + uint32_t index; 1.1352 + rv = 1.1353 + mPrefStyleSheet->InsertRuleInternal(NS_LITERAL_STRING("@namespace svg url(http://www.w3.org/2000/svg);"), 1.1354 + 0, &index); 1.1355 + if (NS_FAILED(rv)) { 1.1356 + mPrefStyleSheet = nullptr; 1.1357 + return rv; 1.1358 + } 1.1359 + rv = 1.1360 + mPrefStyleSheet->InsertRuleInternal(NS_LITERAL_STRING("@namespace url(http://www.w3.org/1999/xhtml);"), 1.1361 + 0, &index); 1.1362 + if (NS_FAILED(rv)) { 1.1363 + mPrefStyleSheet = nullptr; 1.1364 + return rv; 1.1365 + } 1.1366 + 1.1367 + mStyleSet->AppendStyleSheet(nsStyleSet::eUserSheet, mPrefStyleSheet); 1.1368 + return NS_OK; 1.1369 +} 1.1370 + 1.1371 +// XXX We want these after the @namespace rules. Does order matter 1.1372 +// for these rules, or can we call StyleRule::StyleRuleCount() 1.1373 +// and just "append"? 1.1374 +static uint32_t sInsertPrefSheetRulesAt = 2; 1.1375 + 1.1376 +nsresult 1.1377 +PresShell::SetPrefNoScriptRule() 1.1378 +{ 1.1379 + nsresult rv = NS_OK; 1.1380 + 1.1381 + // also handle the case where print is done from print preview 1.1382 + // see bug #342439 for more details 1.1383 + nsIDocument* doc = mDocument; 1.1384 + if (doc->IsStaticDocument()) { 1.1385 + doc = doc->GetOriginalDocument(); 1.1386 + } 1.1387 + 1.1388 + bool scriptEnabled = doc->IsScriptEnabled(); 1.1389 + if (scriptEnabled) { 1.1390 + if (!mPrefStyleSheet) { 1.1391 + rv = CreatePreferenceStyleSheet(); 1.1392 + NS_ENSURE_SUCCESS(rv, rv); 1.1393 + } 1.1394 + 1.1395 + uint32_t index = 0; 1.1396 + mPrefStyleSheet-> 1.1397 + InsertRuleInternal(NS_LITERAL_STRING("noscript{display:none!important}"), 1.1398 + sInsertPrefSheetRulesAt, &index); 1.1399 + } 1.1400 + 1.1401 + return rv; 1.1402 +} 1.1403 + 1.1404 +nsresult PresShell::SetPrefNoFramesRule(void) 1.1405 +{ 1.1406 + NS_ASSERTION(mPresContext,"null prescontext not allowed"); 1.1407 + if (!mPresContext) { 1.1408 + return NS_ERROR_FAILURE; 1.1409 + } 1.1410 + 1.1411 + nsresult rv = NS_OK; 1.1412 + 1.1413 + if (!mPrefStyleSheet) { 1.1414 + rv = CreatePreferenceStyleSheet(); 1.1415 + NS_ENSURE_SUCCESS(rv, rv); 1.1416 + } 1.1417 + 1.1418 + NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null"); 1.1419 + 1.1420 + bool allowSubframes = true; 1.1421 + nsCOMPtr<nsIDocShell> docShell(mPresContext->GetDocShell()); 1.1422 + if (docShell) { 1.1423 + docShell->GetAllowSubframes(&allowSubframes); 1.1424 + } 1.1425 + if (!allowSubframes) { 1.1426 + uint32_t index = 0; 1.1427 + rv = mPrefStyleSheet-> 1.1428 + InsertRuleInternal(NS_LITERAL_STRING("noframes{display:block}"), 1.1429 + sInsertPrefSheetRulesAt, &index); 1.1430 + NS_ENSURE_SUCCESS(rv, rv); 1.1431 + rv = mPrefStyleSheet-> 1.1432 + InsertRuleInternal(NS_LITERAL_STRING("frame, frameset, iframe {display:none!important}"), 1.1433 + sInsertPrefSheetRulesAt, &index); 1.1434 + } 1.1435 + return rv; 1.1436 +} 1.1437 + 1.1438 +nsresult PresShell::SetPrefLinkRules(void) 1.1439 +{ 1.1440 + NS_ASSERTION(mPresContext,"null prescontext not allowed"); 1.1441 + if (!mPresContext) { 1.1442 + return NS_ERROR_FAILURE; 1.1443 + } 1.1444 + 1.1445 + nsresult rv = NS_OK; 1.1446 + 1.1447 + if (!mPrefStyleSheet) { 1.1448 + rv = CreatePreferenceStyleSheet(); 1.1449 + NS_ENSURE_SUCCESS(rv, rv); 1.1450 + } 1.1451 + 1.1452 + NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null"); 1.1453 + 1.1454 + // support default link colors: 1.1455 + // this means the link colors need to be overridable, 1.1456 + // which they are if we put them in the agent stylesheet, 1.1457 + // though if using an override sheet this will cause authors grief still 1.1458 + // In the agent stylesheet, they are !important when we are ignoring document colors 1.1459 + 1.1460 + nscolor linkColor(mPresContext->DefaultLinkColor()); 1.1461 + nscolor activeColor(mPresContext->DefaultActiveLinkColor()); 1.1462 + nscolor visitedColor(mPresContext->DefaultVisitedLinkColor()); 1.1463 + 1.1464 + NS_NAMED_LITERAL_STRING(ruleClose, "}"); 1.1465 + uint32_t index = 0; 1.1466 + nsAutoString strColor; 1.1467 + 1.1468 + // insert a rule to color links: '*|*:link {color: #RRGGBB [!important];}' 1.1469 + ColorToString(linkColor, strColor); 1.1470 + rv = mPrefStyleSheet-> 1.1471 + InsertRuleInternal(NS_LITERAL_STRING("*|*:link{color:") + 1.1472 + strColor + ruleClose, 1.1473 + sInsertPrefSheetRulesAt, &index); 1.1474 + NS_ENSURE_SUCCESS(rv, rv); 1.1475 + 1.1476 + // - visited links: '*|*:visited {color: #RRGGBB [!important];}' 1.1477 + ColorToString(visitedColor, strColor); 1.1478 + rv = mPrefStyleSheet-> 1.1479 + InsertRuleInternal(NS_LITERAL_STRING("*|*:visited{color:") + 1.1480 + strColor + ruleClose, 1.1481 + sInsertPrefSheetRulesAt, &index); 1.1482 + NS_ENSURE_SUCCESS(rv, rv); 1.1483 + 1.1484 + // - active links: '*|*:-moz-any-link:active {color: #RRGGBB [!important];}' 1.1485 + ColorToString(activeColor, strColor); 1.1486 + rv = mPrefStyleSheet-> 1.1487 + InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link:active{color:") + 1.1488 + strColor + ruleClose, 1.1489 + sInsertPrefSheetRulesAt, &index); 1.1490 + NS_ENSURE_SUCCESS(rv, rv); 1.1491 + 1.1492 + bool underlineLinks = 1.1493 + mPresContext->GetCachedBoolPref(kPresContext_UnderlineLinks); 1.1494 + 1.1495 + if (underlineLinks) { 1.1496 + // create a rule to make underlining happen 1.1497 + // '*|*:-moz-any-link {text-decoration:[underline|none];}' 1.1498 + // no need for important, we want these to be overridable 1.1499 + // NOTE: these must go in the agent stylesheet or they cannot be 1.1500 + // overridden by authors 1.1501 + rv = mPrefStyleSheet-> 1.1502 + InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link:not(svg|a){text-decoration:underline}"), 1.1503 + sInsertPrefSheetRulesAt, &index); 1.1504 + } else { 1.1505 + rv = mPrefStyleSheet-> 1.1506 + InsertRuleInternal(NS_LITERAL_STRING("*|*:-moz-any-link{text-decoration:none}"), 1.1507 + sInsertPrefSheetRulesAt, &index); 1.1508 + } 1.1509 + 1.1510 + return rv; 1.1511 +} 1.1512 + 1.1513 +nsresult PresShell::SetPrefFocusRules(void) 1.1514 +{ 1.1515 + NS_ASSERTION(mPresContext,"null prescontext not allowed"); 1.1516 + nsresult result = NS_OK; 1.1517 + 1.1518 + if (!mPresContext) 1.1519 + result = NS_ERROR_FAILURE; 1.1520 + 1.1521 + if (NS_SUCCEEDED(result) && !mPrefStyleSheet) 1.1522 + result = CreatePreferenceStyleSheet(); 1.1523 + 1.1524 + if (NS_SUCCEEDED(result)) { 1.1525 + NS_ASSERTION(mPrefStyleSheet, "prefstylesheet should not be null"); 1.1526 + 1.1527 + if (mPresContext->GetUseFocusColors()) { 1.1528 + nscolor focusBackground(mPresContext->FocusBackgroundColor()); 1.1529 + nscolor focusText(mPresContext->FocusTextColor()); 1.1530 + 1.1531 + // insert a rule to make focus the preferred color 1.1532 + uint32_t index = 0; 1.1533 + nsAutoString strRule, strColor; 1.1534 + 1.1535 + /////////////////////////////////////////////////////////////// 1.1536 + // - focus: '*:focus 1.1537 + ColorToString(focusText,strColor); 1.1538 + strRule.AppendLiteral("*:focus,*:focus>font {color: "); 1.1539 + strRule.Append(strColor); 1.1540 + strRule.AppendLiteral(" !important; background-color: "); 1.1541 + ColorToString(focusBackground,strColor); 1.1542 + strRule.Append(strColor); 1.1543 + strRule.AppendLiteral(" !important; } "); 1.1544 + // insert the rules 1.1545 + result = mPrefStyleSheet-> 1.1546 + InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index); 1.1547 + } 1.1548 + uint8_t focusRingWidth = mPresContext->FocusRingWidth(); 1.1549 + bool focusRingOnAnything = mPresContext->GetFocusRingOnAnything(); 1.1550 + uint8_t focusRingStyle = mPresContext->GetFocusRingStyle(); 1.1551 + 1.1552 + if ((NS_SUCCEEDED(result) && focusRingWidth != 1 && focusRingWidth <= 4 ) || focusRingOnAnything) { 1.1553 + uint32_t index = 0; 1.1554 + nsAutoString strRule; 1.1555 + if (!focusRingOnAnything) 1.1556 + strRule.AppendLiteral("*|*:link:focus, *|*:visited"); // If we only want focus rings on the normal things like links 1.1557 + strRule.AppendLiteral(":focus {outline: "); // For example 3px dotted WindowText (maximum 4) 1.1558 + strRule.AppendInt(focusRingWidth); 1.1559 + if (focusRingStyle == 0) // solid 1.1560 + strRule.AppendLiteral("px solid -moz-mac-focusring !important; -moz-outline-radius: 3px; outline-offset: 1px; } "); 1.1561 + else // dotted 1.1562 + strRule.AppendLiteral("px dotted WindowText !important; } "); 1.1563 + // insert the rules 1.1564 + result = mPrefStyleSheet-> 1.1565 + InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index); 1.1566 + NS_ENSURE_SUCCESS(result, result); 1.1567 + if (focusRingWidth != 1) { 1.1568 + // If the focus ring width is different from the default, fix buttons with rings 1.1569 + strRule.AssignLiteral("button::-moz-focus-inner, input[type=\"reset\"]::-moz-focus-inner,"); 1.1570 + strRule.AppendLiteral("input[type=\"button\"]::-moz-focus-inner, "); 1.1571 + strRule.AppendLiteral("input[type=\"submit\"]::-moz-focus-inner { padding: 1px 2px 1px 2px; border: "); 1.1572 + strRule.AppendInt(focusRingWidth); 1.1573 + if (focusRingStyle == 0) // solid 1.1574 + strRule.AppendLiteral("px solid transparent !important; } "); 1.1575 + else 1.1576 + strRule.AppendLiteral("px dotted transparent !important; } "); 1.1577 + result = mPrefStyleSheet-> 1.1578 + InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index); 1.1579 + NS_ENSURE_SUCCESS(result, result); 1.1580 + 1.1581 + strRule.AssignLiteral("button:focus::-moz-focus-inner, input[type=\"reset\"]:focus::-moz-focus-inner,"); 1.1582 + strRule.AppendLiteral("input[type=\"button\"]:focus::-moz-focus-inner, input[type=\"submit\"]:focus::-moz-focus-inner {"); 1.1583 + strRule.AppendLiteral("border-color: ButtonText !important; }"); 1.1584 + result = mPrefStyleSheet-> 1.1585 + InsertRuleInternal(strRule, sInsertPrefSheetRulesAt, &index); 1.1586 + } 1.1587 + } 1.1588 + } 1.1589 + return result; 1.1590 +} 1.1591 + 1.1592 +void 1.1593 +PresShell::AddUserSheet(nsISupports* aSheet) 1.1594 +{ 1.1595 + // Make sure this does what nsDocumentViewer::CreateStyleSet does wrt 1.1596 + // ordering. We want this new sheet to come after all the existing stylesheet 1.1597 + // service sheets, but before other user sheets; see nsIStyleSheetService.idl 1.1598 + // for the ordering. Just remove and readd all the nsStyleSheetService 1.1599 + // sheets. 1.1600 + nsCOMPtr<nsIStyleSheetService> dummy = 1.1601 + do_GetService(NS_STYLESHEETSERVICE_CONTRACTID); 1.1602 + 1.1603 + mStyleSet->BeginUpdate(); 1.1604 + 1.1605 + nsStyleSheetService *sheetService = nsStyleSheetService::gInstance; 1.1606 + nsCOMArray<nsIStyleSheet> & userSheets = *sheetService->UserStyleSheets(); 1.1607 + int32_t i; 1.1608 + // Iterate forwards when removing so the searches for RemoveStyleSheet are as 1.1609 + // short as possible. 1.1610 + for (i = 0; i < userSheets.Count(); ++i) { 1.1611 + mStyleSet->RemoveStyleSheet(nsStyleSet::eUserSheet, userSheets[i]); 1.1612 + } 1.1613 + 1.1614 + // Now iterate backwards, so that the order of userSheets will be the same as 1.1615 + // the order of sheets from it in the style set. 1.1616 + for (i = userSheets.Count() - 1; i >= 0; --i) { 1.1617 + mStyleSet->PrependStyleSheet(nsStyleSet::eUserSheet, userSheets[i]); 1.1618 + } 1.1619 + 1.1620 + mStyleSet->EndUpdate(); 1.1621 + 1.1622 + ReconstructStyleData(); 1.1623 +} 1.1624 + 1.1625 +void 1.1626 +PresShell::AddAgentSheet(nsISupports* aSheet) 1.1627 +{ 1.1628 + // Make sure this does what nsDocumentViewer::CreateStyleSet does 1.1629 + // wrt ordering. 1.1630 + nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet); 1.1631 + if (!sheet) { 1.1632 + return; 1.1633 + } 1.1634 + 1.1635 + mStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet); 1.1636 + ReconstructStyleData(); 1.1637 +} 1.1638 + 1.1639 +void 1.1640 +PresShell::AddAuthorSheet(nsISupports* aSheet) 1.1641 +{ 1.1642 + nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet); 1.1643 + if (!sheet) { 1.1644 + return; 1.1645 + } 1.1646 + 1.1647 + // Document specific "additional" Author sheets should be stronger than the ones 1.1648 + // added with the StyleSheetService. 1.1649 + nsIStyleSheet* firstAuthorSheet = mDocument->FirstAdditionalAuthorSheet(); 1.1650 + if (firstAuthorSheet) { 1.1651 + mStyleSet->InsertStyleSheetBefore(nsStyleSet::eDocSheet, sheet, firstAuthorSheet); 1.1652 + } else { 1.1653 + mStyleSet->AppendStyleSheet(nsStyleSet::eDocSheet, sheet); 1.1654 + } 1.1655 + 1.1656 + ReconstructStyleData(); 1.1657 +} 1.1658 + 1.1659 +void 1.1660 +PresShell::RemoveSheet(nsStyleSet::sheetType aType, nsISupports* aSheet) 1.1661 +{ 1.1662 + nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet); 1.1663 + if (!sheet) { 1.1664 + return; 1.1665 + } 1.1666 + 1.1667 + mStyleSet->RemoveStyleSheet(aType, sheet); 1.1668 + ReconstructStyleData(); 1.1669 +} 1.1670 + 1.1671 +NS_IMETHODIMP 1.1672 +PresShell::SetDisplaySelection(int16_t aToggle) 1.1673 +{ 1.1674 + mSelection->SetDisplaySelection(aToggle); 1.1675 + return NS_OK; 1.1676 +} 1.1677 + 1.1678 +NS_IMETHODIMP 1.1679 +PresShell::GetDisplaySelection(int16_t *aToggle) 1.1680 +{ 1.1681 + *aToggle = mSelection->GetDisplaySelection(); 1.1682 + return NS_OK; 1.1683 +} 1.1684 + 1.1685 +NS_IMETHODIMP 1.1686 +PresShell::GetSelection(SelectionType aType, nsISelection **aSelection) 1.1687 +{ 1.1688 + if (!aSelection || !mSelection) 1.1689 + return NS_ERROR_NULL_POINTER; 1.1690 + 1.1691 + *aSelection = mSelection->GetSelection(aType); 1.1692 + 1.1693 + if (!(*aSelection)) 1.1694 + return NS_ERROR_INVALID_ARG; 1.1695 + 1.1696 + NS_ADDREF(*aSelection); 1.1697 + 1.1698 + return NS_OK; 1.1699 +} 1.1700 + 1.1701 +Selection* 1.1702 +PresShell::GetCurrentSelection(SelectionType aType) 1.1703 +{ 1.1704 + if (!mSelection) 1.1705 + return nullptr; 1.1706 + 1.1707 + return mSelection->GetSelection(aType); 1.1708 +} 1.1709 + 1.1710 +NS_IMETHODIMP 1.1711 +PresShell::ScrollSelectionIntoView(SelectionType aType, SelectionRegion aRegion, 1.1712 + int16_t aFlags) 1.1713 +{ 1.1714 + if (!mSelection) 1.1715 + return NS_ERROR_NULL_POINTER; 1.1716 + 1.1717 + return mSelection->ScrollSelectionIntoView(aType, aRegion, aFlags); 1.1718 +} 1.1719 + 1.1720 +NS_IMETHODIMP 1.1721 +PresShell::RepaintSelection(SelectionType aType) 1.1722 +{ 1.1723 + if (!mSelection) 1.1724 + return NS_ERROR_NULL_POINTER; 1.1725 + 1.1726 + return mSelection->RepaintSelection(aType); 1.1727 +} 1.1728 + 1.1729 +// Make shell be a document observer 1.1730 +void 1.1731 +PresShell::BeginObservingDocument() 1.1732 +{ 1.1733 + if (mDocument && !mIsDestroying) { 1.1734 + mDocument->AddObserver(this); 1.1735 + if (mIsDocumentGone) { 1.1736 + NS_WARNING("Adding a presshell that was disconnected from the document " 1.1737 + "as a document observer? Sounds wrong..."); 1.1738 + mIsDocumentGone = false; 1.1739 + } 1.1740 + } 1.1741 +} 1.1742 + 1.1743 +// Make shell stop being a document observer 1.1744 +void 1.1745 +PresShell::EndObservingDocument() 1.1746 +{ 1.1747 + // XXXbz do we need to tell the frame constructor that the document 1.1748 + // is gone, perhaps? Except for printing it's NOT gone, sometimes. 1.1749 + mIsDocumentGone = true; 1.1750 + if (mDocument) { 1.1751 + mDocument->RemoveObserver(this); 1.1752 + } 1.1753 +} 1.1754 + 1.1755 +#ifdef DEBUG_kipp 1.1756 +char* nsPresShell_ReflowStackPointerTop; 1.1757 +#endif 1.1758 + 1.1759 +nsresult 1.1760 +PresShell::Initialize(nscoord aWidth, nscoord aHeight) 1.1761 +{ 1.1762 + if (mIsDestroying) { 1.1763 + return NS_OK; 1.1764 + } 1.1765 + 1.1766 + if (!mDocument) { 1.1767 + // Nothing to do 1.1768 + return NS_OK; 1.1769 + } 1.1770 + 1.1771 + mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now(); 1.1772 + 1.1773 + NS_ASSERTION(!mDidInitialize, "Why are we being called?"); 1.1774 + 1.1775 + nsCOMPtr<nsIPresShell> kungFuDeathGrip(this); 1.1776 + mDidInitialize = true; 1.1777 + 1.1778 +#ifdef DEBUG 1.1779 + if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { 1.1780 + if (mDocument) { 1.1781 + nsIURI *uri = mDocument->GetDocumentURI(); 1.1782 + if (uri) { 1.1783 + nsAutoCString url; 1.1784 + uri->GetSpec(url); 1.1785 + printf("*** PresShell::Initialize (this=%p, url='%s')\n", (void*)this, url.get()); 1.1786 + } 1.1787 + } 1.1788 + } 1.1789 +#endif 1.1790 + 1.1791 + if (mCaret) 1.1792 + mCaret->EraseCaret(); 1.1793 + 1.1794 + // XXX Do a full invalidate at the beginning so that invalidates along 1.1795 + // the way don't have region accumulation issues? 1.1796 + 1.1797 + mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight)); 1.1798 + 1.1799 + // Get the root frame from the frame manager 1.1800 + // XXXbz it would be nice to move this somewhere else... like frame manager 1.1801 + // Init(), say. But we need to make sure our views are all set up by the 1.1802 + // time we do this! 1.1803 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.1804 + NS_ASSERTION(!rootFrame, "How did that happen, exactly?"); 1.1805 + if (!rootFrame) { 1.1806 + nsAutoScriptBlocker scriptBlocker; 1.1807 + mFrameConstructor->BeginUpdate(); 1.1808 + rootFrame = mFrameConstructor->ConstructRootFrame(); 1.1809 + mFrameConstructor->SetRootFrame(rootFrame); 1.1810 + mFrameConstructor->EndUpdate(); 1.1811 + } 1.1812 + 1.1813 + NS_ENSURE_STATE(!mHaveShutDown); 1.1814 + 1.1815 + if (!rootFrame) { 1.1816 + return NS_ERROR_OUT_OF_MEMORY; 1.1817 + } 1.1818 + 1.1819 + for (nsIFrame* f = rootFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) { 1.1820 + if (f->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) { 1.1821 + f->InvalidateFrameSubtree(); 1.1822 + f->RemoveStateBits(NS_FRAME_NO_COMPONENT_ALPHA); 1.1823 + } 1.1824 + } 1.1825 + 1.1826 + Element *root = mDocument->GetRootElement(); 1.1827 + 1.1828 + if (root) { 1.1829 + { 1.1830 + nsAutoCauseReflowNotifier reflowNotifier(this); 1.1831 + mFrameConstructor->BeginUpdate(); 1.1832 + 1.1833 + // Have the style sheet processor construct frame for the root 1.1834 + // content object down 1.1835 + mFrameConstructor->ContentInserted(nullptr, root, nullptr, false); 1.1836 + VERIFY_STYLE_TREE; 1.1837 + 1.1838 + // Something in mFrameConstructor->ContentInserted may have caused 1.1839 + // Destroy() to get called, bug 337586. 1.1840 + NS_ENSURE_STATE(!mHaveShutDown); 1.1841 + 1.1842 + mFrameConstructor->EndUpdate(); 1.1843 + } 1.1844 + 1.1845 + // nsAutoScriptBlocker going out of scope may have killed us too 1.1846 + NS_ENSURE_STATE(!mHaveShutDown); 1.1847 + 1.1848 + // Run the XBL binding constructors for any new frames we've constructed 1.1849 + mDocument->BindingManager()->ProcessAttachedQueue(); 1.1850 + 1.1851 + // Constructors may have killed us too 1.1852 + NS_ENSURE_STATE(!mHaveShutDown); 1.1853 + 1.1854 + // Now flush out pending restyles before we actually reflow, in 1.1855 + // case XBL constructors changed styles somewhere. 1.1856 + { 1.1857 + nsAutoScriptBlocker scriptBlocker; 1.1858 + mPresContext->RestyleManager()->ProcessPendingRestyles(); 1.1859 + } 1.1860 + 1.1861 + // And that might have run _more_ XBL constructors 1.1862 + NS_ENSURE_STATE(!mHaveShutDown); 1.1863 + } 1.1864 + 1.1865 + NS_ASSERTION(rootFrame, "How did that happen?"); 1.1866 + 1.1867 + // Note: when the frame was created above it had the NS_FRAME_IS_DIRTY bit 1.1868 + // set, but XBL processing could have caused a reflow which clears it. 1.1869 + if (MOZ_LIKELY(rootFrame->GetStateBits() & NS_FRAME_IS_DIRTY)) { 1.1870 + // Unset the DIRTY bits so that FrameNeedsReflow() will work right. 1.1871 + rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY | 1.1872 + NS_FRAME_HAS_DIRTY_CHILDREN); 1.1873 + NS_ASSERTION(!mDirtyRoots.Contains(rootFrame), 1.1874 + "Why is the root in mDirtyRoots already?"); 1.1875 + FrameNeedsReflow(rootFrame, eResize, NS_FRAME_IS_DIRTY); 1.1876 + NS_ASSERTION(mDirtyRoots.Contains(rootFrame), 1.1877 + "Should be in mDirtyRoots now"); 1.1878 + NS_ASSERTION(mReflowScheduled, "Why no reflow scheduled?"); 1.1879 + } 1.1880 + 1.1881 + // Restore our root scroll position now if we're getting here after EndLoad 1.1882 + // got called, since this is our one chance to do it. Note that we need not 1.1883 + // have reflowed for this to work; when the scrollframe is finally reflowed 1.1884 + // it'll pick up the position we store in it here. 1.1885 + if (!mDocumentLoading) { 1.1886 + RestoreRootScrollPosition(); 1.1887 + } 1.1888 + 1.1889 + // For printing, we just immediately unsuppress. 1.1890 + if (!mPresContext->IsPaginated()) { 1.1891 + // Kick off a one-shot timer based off our pref value. When this timer 1.1892 + // fires, if painting is still locked down, then we will go ahead and 1.1893 + // trigger a full invalidate and allow painting to proceed normally. 1.1894 + mPaintingSuppressed = true; 1.1895 + // Don't suppress painting if the document isn't loading. 1.1896 + nsIDocument::ReadyState readyState = mDocument->GetReadyStateEnum(); 1.1897 + if (readyState != nsIDocument::READYSTATE_COMPLETE) { 1.1898 + mPaintSuppressionTimer = do_CreateInstance("@mozilla.org/timer;1"); 1.1899 + } 1.1900 + if (!mPaintSuppressionTimer) { 1.1901 + mPaintingSuppressed = false; 1.1902 + } else { 1.1903 + // Initialize the timer. 1.1904 + 1.1905 + // Default to PAINTLOCK_EVENT_DELAY if we can't get the pref value. 1.1906 + int32_t delay = 1.1907 + Preferences::GetInt("nglayout.initialpaint.delay", 1.1908 + PAINTLOCK_EVENT_DELAY); 1.1909 + 1.1910 + mPaintSuppressionTimer->InitWithFuncCallback(sPaintSuppressionCallback, 1.1911 + this, delay, 1.1912 + nsITimer::TYPE_ONE_SHOT); 1.1913 + } 1.1914 + } 1.1915 + 1.1916 + if (root && root->IsXUL()) { 1.1917 + mozilla::Telemetry::AccumulateTimeDelta(Telemetry::XUL_INITIAL_FRAME_CONSTRUCTION, 1.1918 + timerStart); 1.1919 + } 1.1920 + 1.1921 + return NS_OK; //XXX this needs to be real. MMP 1.1922 +} 1.1923 + 1.1924 +void 1.1925 +PresShell::sPaintSuppressionCallback(nsITimer *aTimer, void* aPresShell) 1.1926 +{ 1.1927 + nsRefPtr<PresShell> self = static_cast<PresShell*>(aPresShell); 1.1928 + if (self) 1.1929 + self->UnsuppressPainting(); 1.1930 +} 1.1931 + 1.1932 +void 1.1933 +PresShell::AsyncResizeEventCallback(nsITimer* aTimer, void* aPresShell) 1.1934 +{ 1.1935 + static_cast<PresShell*>(aPresShell)->FireResizeEvent(); 1.1936 +} 1.1937 + 1.1938 +nsresult 1.1939 +PresShell::ResizeReflowOverride(nscoord aWidth, nscoord aHeight) 1.1940 +{ 1.1941 + mViewportOverridden = true; 1.1942 + return ResizeReflowIgnoreOverride(aWidth, aHeight); 1.1943 +} 1.1944 + 1.1945 +nsresult 1.1946 +PresShell::ResizeReflow(nscoord aWidth, nscoord aHeight) 1.1947 +{ 1.1948 + if (mViewportOverridden) { 1.1949 + // The viewport has been overridden, and this reflow request 1.1950 + // didn't ask to ignore the override. Pretend it didn't happen. 1.1951 + return NS_OK; 1.1952 + } 1.1953 + return ResizeReflowIgnoreOverride(aWidth, aHeight); 1.1954 +} 1.1955 + 1.1956 +nsresult 1.1957 +PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight) 1.1958 +{ 1.1959 + NS_PRECONDITION(!mIsReflowing, "Shouldn't be in reflow here!"); 1.1960 + NS_PRECONDITION(aWidth != NS_UNCONSTRAINEDSIZE, 1.1961 + "shouldn't use unconstrained widths anymore"); 1.1962 + 1.1963 + // If we don't have a root frame yet, that means we haven't had our initial 1.1964 + // reflow... If that's the case, and aWidth or aHeight is unconstrained, 1.1965 + // ignore them altogether. 1.1966 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.1967 + if (!rootFrame && aHeight == NS_UNCONSTRAINEDSIZE) { 1.1968 + // We can't do the work needed for SizeToContent without a root 1.1969 + // frame, and we want to return before setting the visible area. 1.1970 + return NS_ERROR_NOT_AVAILABLE; 1.1971 + } 1.1972 + 1.1973 + mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight)); 1.1974 + 1.1975 + // There isn't anything useful we can do if the initial reflow hasn't happened. 1.1976 + if (!rootFrame) { 1.1977 + return NS_OK; 1.1978 + } 1.1979 + 1.1980 + nsRefPtr<nsViewManager> viewManagerDeathGrip = mViewManager; 1.1981 + // Take this ref after viewManager so it'll make sure to go away first. 1.1982 + nsCOMPtr<nsIPresShell> kungFuDeathGrip(this); 1.1983 + 1.1984 + if (!GetPresContext()->SupressingResizeReflow()) { 1.1985 + // Have to make sure that the content notifications are flushed before we 1.1986 + // start messing with the frame model; otherwise we can get content doubling. 1.1987 + mDocument->FlushPendingNotifications(Flush_ContentAndNotify); 1.1988 + 1.1989 + // Make sure style is up to date 1.1990 + { 1.1991 + nsAutoScriptBlocker scriptBlocker; 1.1992 + mPresContext->RestyleManager()->ProcessPendingRestyles(); 1.1993 + } 1.1994 + 1.1995 + rootFrame = mFrameConstructor->GetRootFrame(); 1.1996 + if (!mIsDestroying && rootFrame) { 1.1997 + // XXX Do a full invalidate at the beginning so that invalidates along 1.1998 + // the way don't have region accumulation issues? 1.1999 + 1.2000 + { 1.2001 + nsAutoCauseReflowNotifier crNotifier(this); 1.2002 + WillDoReflow(); 1.2003 + 1.2004 + // Kick off a top-down reflow 1.2005 + AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow); 1.2006 + nsViewManager::AutoDisableRefresh refreshBlocker(mViewManager); 1.2007 + 1.2008 + mDirtyRoots.RemoveElement(rootFrame); 1.2009 + DoReflow(rootFrame, true); 1.2010 + } 1.2011 + 1.2012 + DidDoReflow(true, false); 1.2013 + } 1.2014 + } 1.2015 + 1.2016 + rootFrame = mFrameConstructor->GetRootFrame(); 1.2017 + if (aHeight == NS_UNCONSTRAINEDSIZE && rootFrame) { 1.2018 + mPresContext->SetVisibleArea( 1.2019 + nsRect(0, 0, aWidth, rootFrame->GetRect().height)); 1.2020 + } 1.2021 + 1.2022 + if (!mIsDestroying && !mResizeEvent.IsPending() && 1.2023 + !mAsyncResizeTimerIsActive) { 1.2024 + if (mInResize) { 1.2025 + if (!mAsyncResizeEventTimer) { 1.2026 + mAsyncResizeEventTimer = do_CreateInstance("@mozilla.org/timer;1"); 1.2027 + } 1.2028 + if (mAsyncResizeEventTimer) { 1.2029 + mAsyncResizeTimerIsActive = true; 1.2030 + mAsyncResizeEventTimer->InitWithFuncCallback(AsyncResizeEventCallback, 1.2031 + this, 15, 1.2032 + nsITimer::TYPE_ONE_SHOT); 1.2033 + } 1.2034 + } else { 1.2035 + nsRefPtr<nsRunnableMethod<PresShell> > resizeEvent = 1.2036 + NS_NewRunnableMethod(this, &PresShell::FireResizeEvent); 1.2037 + if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent))) { 1.2038 + mResizeEvent = resizeEvent; 1.2039 + mDocument->SetNeedStyleFlush(); 1.2040 + } 1.2041 + } 1.2042 + } 1.2043 + 1.2044 + return NS_OK; //XXX this needs to be real. MMP 1.2045 +} 1.2046 + 1.2047 +void 1.2048 +PresShell::FireResizeEvent() 1.2049 +{ 1.2050 + if (mAsyncResizeTimerIsActive) { 1.2051 + mAsyncResizeTimerIsActive = false; 1.2052 + mAsyncResizeEventTimer->Cancel(); 1.2053 + } 1.2054 + mResizeEvent.Revoke(); 1.2055 + 1.2056 + if (mIsDocumentGone) 1.2057 + return; 1.2058 + 1.2059 + //Send resize event from here. 1.2060 + WidgetEvent event(true, NS_RESIZE_EVENT); 1.2061 + nsEventStatus status = nsEventStatus_eIgnore; 1.2062 + 1.2063 + nsPIDOMWindow *window = mDocument->GetWindow(); 1.2064 + if (window) { 1.2065 + nsCOMPtr<nsIPresShell> kungFuDeathGrip(this); 1.2066 + mInResize = true; 1.2067 + EventDispatcher::Dispatch(window, mPresContext, &event, nullptr, &status); 1.2068 + mInResize = false; 1.2069 + } 1.2070 +} 1.2071 + 1.2072 +void 1.2073 +PresShell::SetIgnoreFrameDestruction(bool aIgnore) 1.2074 +{ 1.2075 + if (mDocument) { 1.2076 + // We need to tell the ImageLoader to drop all its references to frames 1.2077 + // because they're about to go away and it won't get notifications of that. 1.2078 + mDocument->StyleImageLoader()->ClearFrames(); 1.2079 + } 1.2080 + mIgnoreFrameDestruction = aIgnore; 1.2081 +} 1.2082 + 1.2083 +void 1.2084 +PresShell::NotifyDestroyingFrame(nsIFrame* aFrame) 1.2085 +{ 1.2086 + if (!mIgnoreFrameDestruction) { 1.2087 + mDocument->StyleImageLoader()->DropRequestsForFrame(aFrame); 1.2088 + 1.2089 + mFrameConstructor->NotifyDestroyingFrame(aFrame); 1.2090 + 1.2091 + for (int32_t idx = mDirtyRoots.Length(); idx; ) { 1.2092 + --idx; 1.2093 + if (mDirtyRoots[idx] == aFrame) { 1.2094 + mDirtyRoots.RemoveElementAt(idx); 1.2095 + } 1.2096 + } 1.2097 + 1.2098 + // Remove frame properties 1.2099 + mPresContext->NotifyDestroyingFrame(aFrame); 1.2100 + 1.2101 + if (aFrame == mCurrentEventFrame) { 1.2102 + mCurrentEventContent = aFrame->GetContent(); 1.2103 + mCurrentEventFrame = nullptr; 1.2104 + } 1.2105 + 1.2106 + #ifdef DEBUG 1.2107 + if (aFrame == mDrawEventTargetFrame) { 1.2108 + mDrawEventTargetFrame = nullptr; 1.2109 + } 1.2110 + #endif 1.2111 + 1.2112 + for (unsigned int i=0; i < mCurrentEventFrameStack.Length(); i++) { 1.2113 + if (aFrame == mCurrentEventFrameStack.ElementAt(i)) { 1.2114 + //One of our stack frames was deleted. Get its content so that when we 1.2115 + //pop it we can still get its new frame from its content 1.2116 + nsIContent *currentEventContent = aFrame->GetContent(); 1.2117 + mCurrentEventContentStack.ReplaceObjectAt(currentEventContent, i); 1.2118 + mCurrentEventFrameStack[i] = nullptr; 1.2119 + } 1.2120 + } 1.2121 + 1.2122 + mFramesToDirty.RemoveEntry(aFrame); 1.2123 + } else { 1.2124 + // We must delete this property in situ so that its destructor removes the 1.2125 + // frame from FrameLayerBuilder::DisplayItemData::mFrameList -- otherwise 1.2126 + // the DisplayItemData destructor will use the destroyed frame when it 1.2127 + // tries to remove it from the (array) value of this property. 1.2128 + mPresContext->PropertyTable()-> 1.2129 + Delete(aFrame, FrameLayerBuilder::LayerManagerDataProperty()); 1.2130 + } 1.2131 +} 1.2132 + 1.2133 +already_AddRefed<nsCaret> PresShell::GetCaret() const 1.2134 +{ 1.2135 + nsRefPtr<nsCaret> caret = mCaret; 1.2136 + return caret.forget(); 1.2137 +} 1.2138 + 1.2139 +void PresShell::MaybeInvalidateCaretPosition() 1.2140 +{ 1.2141 + if (mCaret) { 1.2142 + mCaret->InvalidateOutsideCaret(); 1.2143 + } 1.2144 +} 1.2145 + 1.2146 +void PresShell::SetCaret(nsCaret *aNewCaret) 1.2147 +{ 1.2148 + mCaret = aNewCaret; 1.2149 +} 1.2150 + 1.2151 +void PresShell::RestoreCaret() 1.2152 +{ 1.2153 + mCaret = mOriginalCaret; 1.2154 +} 1.2155 + 1.2156 +NS_IMETHODIMP PresShell::SetCaretEnabled(bool aInEnable) 1.2157 +{ 1.2158 + bool oldEnabled = mCaretEnabled; 1.2159 + 1.2160 + mCaretEnabled = aInEnable; 1.2161 + 1.2162 + if (mCaret && (mCaretEnabled != oldEnabled)) 1.2163 + { 1.2164 +/* Don't change the caret's selection here! This was an evil side-effect of SetCaretEnabled() 1.2165 + nsCOMPtr<nsIDOMSelection> domSel; 1.2166 + if (NS_SUCCEEDED(GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(domSel))) && domSel) 1.2167 + mCaret->SetCaretDOMSelection(domSel); 1.2168 +*/ 1.2169 + mCaret->SetCaretVisible(mCaretEnabled); 1.2170 + } 1.2171 + 1.2172 + return NS_OK; 1.2173 +} 1.2174 + 1.2175 +NS_IMETHODIMP PresShell::SetCaretReadOnly(bool aReadOnly) 1.2176 +{ 1.2177 + if (mCaret) 1.2178 + mCaret->SetCaretReadOnly(aReadOnly); 1.2179 + return NS_OK; 1.2180 +} 1.2181 + 1.2182 +NS_IMETHODIMP PresShell::GetCaretEnabled(bool *aOutEnabled) 1.2183 +{ 1.2184 + NS_ENSURE_ARG_POINTER(aOutEnabled); 1.2185 + *aOutEnabled = mCaretEnabled; 1.2186 + return NS_OK; 1.2187 +} 1.2188 + 1.2189 +NS_IMETHODIMP PresShell::SetCaretVisibilityDuringSelection(bool aVisibility) 1.2190 +{ 1.2191 + if (mCaret) 1.2192 + mCaret->SetVisibilityDuringSelection(aVisibility); 1.2193 + return NS_OK; 1.2194 +} 1.2195 + 1.2196 +NS_IMETHODIMP PresShell::GetCaretVisible(bool *aOutIsVisible) 1.2197 +{ 1.2198 + *aOutIsVisible = false; 1.2199 + if (mCaret) { 1.2200 + nsresult rv = mCaret->GetCaretVisible(aOutIsVisible); 1.2201 + NS_ENSURE_SUCCESS(rv,rv); 1.2202 + } 1.2203 + return NS_OK; 1.2204 +} 1.2205 + 1.2206 +NS_IMETHODIMP PresShell::SetSelectionFlags(int16_t aInEnable) 1.2207 +{ 1.2208 + mSelectionFlags = aInEnable; 1.2209 + return NS_OK; 1.2210 +} 1.2211 + 1.2212 +NS_IMETHODIMP PresShell::GetSelectionFlags(int16_t *aOutEnable) 1.2213 +{ 1.2214 + if (!aOutEnable) 1.2215 + return NS_ERROR_INVALID_ARG; 1.2216 + *aOutEnable = mSelectionFlags; 1.2217 + return NS_OK; 1.2218 +} 1.2219 + 1.2220 +//implementation of nsISelectionController 1.2221 + 1.2222 +NS_IMETHODIMP 1.2223 +PresShell::CharacterMove(bool aForward, bool aExtend) 1.2224 +{ 1.2225 + return mSelection->CharacterMove(aForward, aExtend); 1.2226 +} 1.2227 + 1.2228 +NS_IMETHODIMP 1.2229 +PresShell::CharacterExtendForDelete() 1.2230 +{ 1.2231 + return mSelection->CharacterExtendForDelete(); 1.2232 +} 1.2233 + 1.2234 +NS_IMETHODIMP 1.2235 +PresShell::CharacterExtendForBackspace() 1.2236 +{ 1.2237 + return mSelection->CharacterExtendForBackspace(); 1.2238 +} 1.2239 + 1.2240 +NS_IMETHODIMP 1.2241 +PresShell::WordMove(bool aForward, bool aExtend) 1.2242 +{ 1.2243 + nsresult result = mSelection->WordMove(aForward, aExtend); 1.2244 +// if we can't go down/up any more we must then move caret completely to 1.2245 +// end/beginning respectively. 1.2246 + if (NS_FAILED(result)) 1.2247 + result = CompleteMove(aForward, aExtend); 1.2248 + return result; 1.2249 +} 1.2250 + 1.2251 +NS_IMETHODIMP 1.2252 +PresShell::WordExtendForDelete(bool aForward) 1.2253 +{ 1.2254 + return mSelection->WordExtendForDelete(aForward); 1.2255 +} 1.2256 + 1.2257 +NS_IMETHODIMP 1.2258 +PresShell::LineMove(bool aForward, bool aExtend) 1.2259 +{ 1.2260 + nsresult result = mSelection->LineMove(aForward, aExtend); 1.2261 +// if we can't go down/up any more we must then move caret completely to 1.2262 +// end/beginning respectively. 1.2263 + if (NS_FAILED(result)) 1.2264 + result = CompleteMove(aForward,aExtend); 1.2265 + return result; 1.2266 +} 1.2267 + 1.2268 +NS_IMETHODIMP 1.2269 +PresShell::IntraLineMove(bool aForward, bool aExtend) 1.2270 +{ 1.2271 + return mSelection->IntraLineMove(aForward, aExtend); 1.2272 +} 1.2273 + 1.2274 + 1.2275 + 1.2276 +NS_IMETHODIMP 1.2277 +PresShell::PageMove(bool aForward, bool aExtend) 1.2278 +{ 1.2279 + nsIScrollableFrame *scrollableFrame = 1.2280 + GetFrameToScrollAsScrollable(nsIPresShell::eVertical); 1.2281 + if (!scrollableFrame) 1.2282 + return NS_OK; 1.2283 + 1.2284 + mSelection->CommonPageMove(aForward, aExtend, scrollableFrame); 1.2285 + // After ScrollSelectionIntoView(), the pending notifications might be 1.2286 + // flushed and PresShell/PresContext/Frames may be dead. See bug 418470. 1.2287 + return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, 1.2288 + nsISelectionController::SELECTION_FOCUS_REGION, 1.2289 + nsISelectionController::SCROLL_SYNCHRONOUS); 1.2290 +} 1.2291 + 1.2292 + 1.2293 + 1.2294 +NS_IMETHODIMP 1.2295 +PresShell::ScrollPage(bool aForward) 1.2296 +{ 1.2297 + nsIScrollableFrame* scrollFrame = 1.2298 + GetFrameToScrollAsScrollable(nsIPresShell::eVertical); 1.2299 + if (scrollFrame) { 1.2300 + scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1), 1.2301 + nsIScrollableFrame::PAGES, 1.2302 + nsIScrollableFrame::SMOOTH); 1.2303 + } 1.2304 + return NS_OK; 1.2305 +} 1.2306 + 1.2307 +NS_IMETHODIMP 1.2308 +PresShell::ScrollLine(bool aForward) 1.2309 +{ 1.2310 + nsIScrollableFrame* scrollFrame = 1.2311 + GetFrameToScrollAsScrollable(nsIPresShell::eVertical); 1.2312 + if (scrollFrame) { 1.2313 + int32_t lineCount = Preferences::GetInt("toolkit.scrollbox.verticalScrollDistance", 1.2314 + NS_DEFAULT_VERTICAL_SCROLL_DISTANCE); 1.2315 + scrollFrame->ScrollBy(nsIntPoint(0, aForward ? lineCount : -lineCount), 1.2316 + nsIScrollableFrame::LINES, 1.2317 + nsIScrollableFrame::SMOOTH); 1.2318 + } 1.2319 + return NS_OK; 1.2320 +} 1.2321 + 1.2322 +NS_IMETHODIMP 1.2323 +PresShell::ScrollCharacter(bool aRight) 1.2324 +{ 1.2325 + nsIScrollableFrame* scrollFrame = 1.2326 + GetFrameToScrollAsScrollable(nsIPresShell::eHorizontal); 1.2327 + if (scrollFrame) { 1.2328 + int32_t h = Preferences::GetInt("toolkit.scrollbox.horizontalScrollDistance", 1.2329 + NS_DEFAULT_HORIZONTAL_SCROLL_DISTANCE); 1.2330 + scrollFrame->ScrollBy(nsIntPoint(aRight ? h : -h, 0), 1.2331 + nsIScrollableFrame::LINES, 1.2332 + nsIScrollableFrame::SMOOTH); 1.2333 + } 1.2334 + return NS_OK; 1.2335 +} 1.2336 + 1.2337 +NS_IMETHODIMP 1.2338 +PresShell::CompleteScroll(bool aForward) 1.2339 +{ 1.2340 + nsIScrollableFrame* scrollFrame = 1.2341 + GetFrameToScrollAsScrollable(nsIPresShell::eVertical); 1.2342 + if (scrollFrame) { 1.2343 + scrollFrame->ScrollBy(nsIntPoint(0, aForward ? 1 : -1), 1.2344 + nsIScrollableFrame::WHOLE, 1.2345 + nsIScrollableFrame::SMOOTH); 1.2346 + } 1.2347 + return NS_OK; 1.2348 +} 1.2349 + 1.2350 +NS_IMETHODIMP 1.2351 +PresShell::CompleteMove(bool aForward, bool aExtend) 1.2352 +{ 1.2353 + // Beware! This may flush notifications via synchronous 1.2354 + // ScrollSelectionIntoView. 1.2355 + nsIContent* limiter = mSelection->GetAncestorLimiter(); 1.2356 + nsIFrame* frame = limiter ? limiter->GetPrimaryFrame() 1.2357 + : FrameConstructor()->GetRootElementFrame(); 1.2358 + if (!frame) 1.2359 + return NS_ERROR_FAILURE; 1.2360 + nsIFrame::CaretPosition pos = 1.2361 + frame->GetExtremeCaretPosition(!aForward); 1.2362 + mSelection->HandleClick(pos.mResultContent, pos.mContentOffset, 1.2363 + pos.mContentOffset, aExtend, false, aForward); 1.2364 + if (limiter) { 1.2365 + // HandleClick resets ancestorLimiter, so set it again. 1.2366 + mSelection->SetAncestorLimiter(limiter); 1.2367 + } 1.2368 + 1.2369 + // After ScrollSelectionIntoView(), the pending notifications might be 1.2370 + // flushed and PresShell/PresContext/Frames may be dead. See bug 418470. 1.2371 + return ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, 1.2372 + nsISelectionController::SELECTION_FOCUS_REGION, 1.2373 + nsISelectionController::SCROLL_SYNCHRONOUS); 1.2374 +} 1.2375 + 1.2376 +NS_IMETHODIMP 1.2377 +PresShell::SelectAll() 1.2378 +{ 1.2379 + return mSelection->SelectAll(); 1.2380 +} 1.2381 + 1.2382 +static void 1.2383 +DoCheckVisibility(nsPresContext* aPresContext, 1.2384 + nsIContent* aNode, 1.2385 + int16_t aStartOffset, 1.2386 + int16_t aEndOffset, 1.2387 + bool* aRetval) 1.2388 +{ 1.2389 + nsIFrame* frame = aNode->GetPrimaryFrame(); 1.2390 + if (!frame) { 1.2391 + // No frame to look at so it must not be visible. 1.2392 + return; 1.2393 + } 1.2394 + 1.2395 + // Start process now to go through all frames to find startOffset. Then check 1.2396 + // chars after that to see if anything until EndOffset is visible. 1.2397 + bool finished = false; 1.2398 + frame->CheckVisibility(aPresContext, aStartOffset, aEndOffset, true, 1.2399 + &finished, aRetval); 1.2400 + // Don't worry about other return value. 1.2401 +} 1.2402 + 1.2403 +NS_IMETHODIMP 1.2404 +PresShell::CheckVisibility(nsIDOMNode *node, int16_t startOffset, int16_t EndOffset, bool *_retval) 1.2405 +{ 1.2406 + if (!node || startOffset>EndOffset || !_retval || startOffset<0 || EndOffset<0) 1.2407 + return NS_ERROR_INVALID_ARG; 1.2408 + *_retval = false; //initialize return parameter 1.2409 + nsCOMPtr<nsIContent> content(do_QueryInterface(node)); 1.2410 + if (!content) 1.2411 + return NS_ERROR_FAILURE; 1.2412 + 1.2413 + DoCheckVisibility(mPresContext, content, startOffset, EndOffset, _retval); 1.2414 + return NS_OK; 1.2415 +} 1.2416 + 1.2417 +nsresult 1.2418 +PresShell::CheckVisibilityContent(nsIContent* aNode, int16_t aStartOffset, 1.2419 + int16_t aEndOffset, bool* aRetval) 1.2420 +{ 1.2421 + if (!aNode || aStartOffset > aEndOffset || !aRetval || 1.2422 + aStartOffset < 0 || aEndOffset < 0) { 1.2423 + return NS_ERROR_INVALID_ARG; 1.2424 + } 1.2425 + 1.2426 + *aRetval = false; 1.2427 + DoCheckVisibility(mPresContext, aNode, aStartOffset, aEndOffset, aRetval); 1.2428 + return NS_OK; 1.2429 +} 1.2430 + 1.2431 +//end implementations nsISelectionController 1.2432 + 1.2433 +nsIFrame* 1.2434 +nsIPresShell::GetRootFrameExternal() const 1.2435 +{ 1.2436 + return mFrameConstructor->GetRootFrame(); 1.2437 +} 1.2438 + 1.2439 +nsIFrame* 1.2440 +nsIPresShell::GetRootScrollFrame() const 1.2441 +{ 1.2442 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.2443 + // Ensure root frame is a viewport frame 1.2444 + if (!rootFrame || nsGkAtoms::viewportFrame != rootFrame->GetType()) 1.2445 + return nullptr; 1.2446 + nsIFrame* theFrame = rootFrame->GetFirstPrincipalChild(); 1.2447 + if (!theFrame || nsGkAtoms::scrollFrame != theFrame->GetType()) 1.2448 + return nullptr; 1.2449 + return theFrame; 1.2450 +} 1.2451 + 1.2452 +nsIScrollableFrame* 1.2453 +nsIPresShell::GetRootScrollFrameAsScrollable() const 1.2454 +{ 1.2455 + nsIFrame* frame = GetRootScrollFrame(); 1.2456 + if (!frame) 1.2457 + return nullptr; 1.2458 + nsIScrollableFrame* scrollableFrame = do_QueryFrame(frame); 1.2459 + NS_ASSERTION(scrollableFrame, 1.2460 + "All scroll frames must implement nsIScrollableFrame"); 1.2461 + return scrollableFrame; 1.2462 +} 1.2463 + 1.2464 +nsIScrollableFrame* 1.2465 +nsIPresShell::GetRootScrollFrameAsScrollableExternal() const 1.2466 +{ 1.2467 + return GetRootScrollFrameAsScrollable(); 1.2468 +} 1.2469 + 1.2470 +nsIPageSequenceFrame* 1.2471 +PresShell::GetPageSequenceFrame() const 1.2472 +{ 1.2473 + nsIFrame* frame = mFrameConstructor->GetPageSequenceFrame(); 1.2474 + return do_QueryFrame(frame); 1.2475 +} 1.2476 + 1.2477 +void 1.2478 +PresShell::BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType) 1.2479 +{ 1.2480 +#ifdef DEBUG 1.2481 + mUpdateCount++; 1.2482 +#endif 1.2483 + mFrameConstructor->BeginUpdate(); 1.2484 + 1.2485 + if (aUpdateType & UPDATE_STYLE) 1.2486 + mStyleSet->BeginUpdate(); 1.2487 +} 1.2488 + 1.2489 +void 1.2490 +PresShell::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType) 1.2491 +{ 1.2492 +#ifdef DEBUG 1.2493 + NS_PRECONDITION(0 != mUpdateCount, "too many EndUpdate's"); 1.2494 + --mUpdateCount; 1.2495 +#endif 1.2496 + 1.2497 + if (aUpdateType & UPDATE_STYLE) { 1.2498 + mStyleSet->EndUpdate(); 1.2499 + if (mStylesHaveChanged || !mChangedScopeStyleRoots.IsEmpty()) 1.2500 + ReconstructStyleData(); 1.2501 + } 1.2502 + 1.2503 + mFrameConstructor->EndUpdate(); 1.2504 +} 1.2505 + 1.2506 +void 1.2507 +PresShell::RestoreRootScrollPosition() 1.2508 +{ 1.2509 + nsIScrollableFrame* scrollableFrame = GetRootScrollFrameAsScrollable(); 1.2510 + if (scrollableFrame) { 1.2511 + scrollableFrame->ScrollToRestoredPosition(); 1.2512 + } 1.2513 +} 1.2514 + 1.2515 +void 1.2516 +PresShell::BeginLoad(nsIDocument *aDocument) 1.2517 +{ 1.2518 + mDocumentLoading = true; 1.2519 + 1.2520 +#ifdef PR_LOGGING 1.2521 + gfxTextPerfMetrics *tp = nullptr; 1.2522 + if (mPresContext) { 1.2523 + tp = mPresContext->GetTextPerfMetrics(); 1.2524 + } 1.2525 + 1.2526 + bool shouldLog = gLog && PR_LOG_TEST(gLog, PR_LOG_DEBUG); 1.2527 + if (shouldLog || tp) { 1.2528 + mLoadBegin = TimeStamp::Now(); 1.2529 + } 1.2530 + 1.2531 + if (shouldLog) { 1.2532 + nsIURI* uri = mDocument->GetDocumentURI(); 1.2533 + nsAutoCString spec; 1.2534 + if (uri) { 1.2535 + uri->GetSpec(spec); 1.2536 + } 1.2537 + PR_LOG(gLog, PR_LOG_DEBUG, 1.2538 + ("(presshell) %p load begin [%s]\n", 1.2539 + this, spec.get())); 1.2540 + } 1.2541 +#endif 1.2542 +} 1.2543 + 1.2544 +void 1.2545 +PresShell::EndLoad(nsIDocument *aDocument) 1.2546 +{ 1.2547 + NS_PRECONDITION(aDocument == mDocument, "Wrong document"); 1.2548 + 1.2549 + RestoreRootScrollPosition(); 1.2550 + 1.2551 + mDocumentLoading = false; 1.2552 +} 1.2553 + 1.2554 +void 1.2555 +PresShell::LoadComplete() 1.2556 +{ 1.2557 +#ifdef PR_LOGGING 1.2558 + gfxTextPerfMetrics *tp = nullptr; 1.2559 + if (mPresContext) { 1.2560 + tp = mPresContext->GetTextPerfMetrics(); 1.2561 + } 1.2562 + 1.2563 + // log load 1.2564 + bool shouldLog = gLog && PR_LOG_TEST(gLog, PR_LOG_DEBUG); 1.2565 + if (shouldLog || tp) { 1.2566 + TimeDuration loadTime = TimeStamp::Now() - mLoadBegin; 1.2567 + nsIURI* uri = mDocument->GetDocumentURI(); 1.2568 + nsAutoCString spec; 1.2569 + if (uri) { 1.2570 + uri->GetSpec(spec); 1.2571 + } 1.2572 + if (shouldLog) { 1.2573 + PR_LOG(gLog, PR_LOG_DEBUG, 1.2574 + ("(presshell) %p load done time-ms: %9.2f [%s]\n", 1.2575 + this, loadTime.ToMilliseconds(), spec.get())); 1.2576 + } 1.2577 + if (tp) { 1.2578 + tp->Accumulate(); 1.2579 + if (tp->cumulative.numChars > 0) { 1.2580 + LogTextPerfStats(tp, this, tp->cumulative, loadTime.ToMilliseconds(), 1.2581 + eLog_loaddone, spec.get()); 1.2582 + } 1.2583 + } 1.2584 + } 1.2585 +#endif 1.2586 +} 1.2587 + 1.2588 +#ifdef DEBUG 1.2589 +void 1.2590 +PresShell::VerifyHasDirtyRootAncestor(nsIFrame* aFrame) 1.2591 +{ 1.2592 + // XXXbz due to bug 372769, can't actually assert anything here... 1.2593 + return; 1.2594 + 1.2595 + // XXXbz shouldn't need this part; remove it once FrameNeedsReflow 1.2596 + // handles the root frame correctly. 1.2597 + if (!aFrame->GetParent()) { 1.2598 + return; 1.2599 + } 1.2600 + 1.2601 + // Make sure that there is a reflow root ancestor of |aFrame| that's 1.2602 + // in mDirtyRoots already. 1.2603 + while (aFrame && (aFrame->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN)) { 1.2604 + if (((aFrame->GetStateBits() & NS_FRAME_REFLOW_ROOT) || 1.2605 + !aFrame->GetParent()) && 1.2606 + mDirtyRoots.Contains(aFrame)) { 1.2607 + return; 1.2608 + } 1.2609 + 1.2610 + aFrame = aFrame->GetParent(); 1.2611 + } 1.2612 + NS_NOTREACHED("Frame has dirty bits set but isn't scheduled to be " 1.2613 + "reflowed?"); 1.2614 +} 1.2615 +#endif 1.2616 + 1.2617 +void 1.2618 +PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty, 1.2619 + nsFrameState aBitToAdd) 1.2620 +{ 1.2621 + NS_PRECONDITION(aBitToAdd == NS_FRAME_IS_DIRTY || 1.2622 + aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN || 1.2623 + !aBitToAdd, 1.2624 + "Unexpected bits being added"); 1.2625 + NS_PRECONDITION(!(aIntrinsicDirty == eStyleChange && 1.2626 + aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN), 1.2627 + "bits don't correspond to style change reason"); 1.2628 + 1.2629 + NS_ASSERTION(!mIsReflowing, "can't mark frame dirty during reflow"); 1.2630 + 1.2631 + // If we've not yet done the initial reflow, then don't bother 1.2632 + // enqueuing a reflow command yet. 1.2633 + if (! mDidInitialize) 1.2634 + return; 1.2635 + 1.2636 + // If we're already destroying, don't bother with this either. 1.2637 + if (mIsDestroying) 1.2638 + return; 1.2639 + 1.2640 +#ifdef DEBUG 1.2641 + //printf("gShellCounter: %d\n", gShellCounter++); 1.2642 + if (mInVerifyReflow) 1.2643 + return; 1.2644 + 1.2645 + if (VERIFY_REFLOW_NOISY_RC & gVerifyReflowFlags) { 1.2646 + printf("\nPresShell@%p: frame %p needs reflow\n", (void*)this, (void*)aFrame); 1.2647 + if (VERIFY_REFLOW_REALLY_NOISY_RC & gVerifyReflowFlags) { 1.2648 + printf("Current content model:\n"); 1.2649 + Element *rootElement = mDocument->GetRootElement(); 1.2650 + if (rootElement) { 1.2651 + rootElement->List(stdout, 0); 1.2652 + } 1.2653 + } 1.2654 + } 1.2655 +#endif 1.2656 + 1.2657 + nsAutoTArray<nsIFrame*, 4> subtrees; 1.2658 + subtrees.AppendElement(aFrame); 1.2659 + 1.2660 + do { 1.2661 + nsIFrame *subtreeRoot = subtrees.ElementAt(subtrees.Length() - 1); 1.2662 + subtrees.RemoveElementAt(subtrees.Length() - 1); 1.2663 + 1.2664 + // Grab |wasDirty| now so we can go ahead and update the bits on 1.2665 + // subtreeRoot. 1.2666 + bool wasDirty = NS_SUBTREE_DIRTY(subtreeRoot); 1.2667 + subtreeRoot->AddStateBits(aBitToAdd); 1.2668 + 1.2669 + // Now if subtreeRoot is a reflow root we can cut off this reflow at it if 1.2670 + // the bit being added is NS_FRAME_HAS_DIRTY_CHILDREN. 1.2671 + bool targetFrameDirty = (aBitToAdd == NS_FRAME_IS_DIRTY); 1.2672 + 1.2673 +#define FRAME_IS_REFLOW_ROOT(_f) \ 1.2674 + ((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && \ 1.2675 + (_f != subtreeRoot || !targetFrameDirty)) 1.2676 + 1.2677 + 1.2678 + // Mark the intrinsic widths as dirty on the frame, all of its ancestors, 1.2679 + // and all of its descendants, if needed: 1.2680 + 1.2681 + if (aIntrinsicDirty != eResize) { 1.2682 + // Mark argument and all ancestors dirty. (Unless we hit a reflow 1.2683 + // root that should contain the reflow. That root could be 1.2684 + // subtreeRoot itself if it's not dirty, or it could be some 1.2685 + // ancestor of subtreeRoot.) 1.2686 + for (nsIFrame *a = subtreeRoot; 1.2687 + a && !FRAME_IS_REFLOW_ROOT(a); 1.2688 + a = a->GetParent()) 1.2689 + a->MarkIntrinsicWidthsDirty(); 1.2690 + } 1.2691 + 1.2692 + if (aIntrinsicDirty == eStyleChange) { 1.2693 + // Mark all descendants dirty (using an nsTArray stack rather than 1.2694 + // recursion). 1.2695 + // Note that nsHTMLReflowState::InitResizeFlags has some similar 1.2696 + // code; see comments there for how and why it differs. 1.2697 + nsAutoTArray<nsIFrame*, 32> stack; 1.2698 + stack.AppendElement(subtreeRoot); 1.2699 + 1.2700 + do { 1.2701 + nsIFrame *f = stack.ElementAt(stack.Length() - 1); 1.2702 + stack.RemoveElementAt(stack.Length() - 1); 1.2703 + 1.2704 + if (f->GetType() == nsGkAtoms::placeholderFrame) { 1.2705 + nsIFrame *oof = nsPlaceholderFrame::GetRealFrameForPlaceholder(f); 1.2706 + if (!nsLayoutUtils::IsProperAncestorFrame(subtreeRoot, oof)) { 1.2707 + // We have another distinct subtree we need to mark. 1.2708 + subtrees.AppendElement(oof); 1.2709 + } 1.2710 + } 1.2711 + 1.2712 + nsIFrame::ChildListIterator lists(f); 1.2713 + for (; !lists.IsDone(); lists.Next()) { 1.2714 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.2715 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.2716 + nsIFrame* kid = childFrames.get(); 1.2717 + kid->MarkIntrinsicWidthsDirty(); 1.2718 + stack.AppendElement(kid); 1.2719 + } 1.2720 + } 1.2721 + } while (stack.Length() != 0); 1.2722 + } 1.2723 + 1.2724 + // Skip setting dirty bits up the tree if we weren't given a bit to add. 1.2725 + if (!aBitToAdd) { 1.2726 + continue; 1.2727 + } 1.2728 + 1.2729 + // Set NS_FRAME_HAS_DIRTY_CHILDREN bits (via nsIFrame::ChildIsDirty) 1.2730 + // up the tree until we reach either a frame that's already dirty or 1.2731 + // a reflow root. 1.2732 + nsIFrame *f = subtreeRoot; 1.2733 + for (;;) { 1.2734 + if (FRAME_IS_REFLOW_ROOT(f) || !f->GetParent()) { 1.2735 + // we've hit a reflow root or the root frame 1.2736 + if (!wasDirty) { 1.2737 + mDirtyRoots.AppendElement(f); 1.2738 + mDocument->SetNeedLayoutFlush(); 1.2739 + } 1.2740 +#ifdef DEBUG 1.2741 + else { 1.2742 + VerifyHasDirtyRootAncestor(f); 1.2743 + } 1.2744 +#endif 1.2745 + 1.2746 + break; 1.2747 + } 1.2748 + 1.2749 + nsIFrame *child = f; 1.2750 + f = f->GetParent(); 1.2751 + wasDirty = NS_SUBTREE_DIRTY(f); 1.2752 + f->ChildIsDirty(child); 1.2753 + NS_ASSERTION(f->GetStateBits() & NS_FRAME_HAS_DIRTY_CHILDREN, 1.2754 + "ChildIsDirty didn't do its job"); 1.2755 + if (wasDirty) { 1.2756 + // This frame was already marked dirty. 1.2757 +#ifdef DEBUG 1.2758 + VerifyHasDirtyRootAncestor(f); 1.2759 +#endif 1.2760 + break; 1.2761 + } 1.2762 + } 1.2763 + } while (subtrees.Length() != 0); 1.2764 + 1.2765 + MaybeScheduleReflow(); 1.2766 +} 1.2767 + 1.2768 +void 1.2769 +PresShell::FrameNeedsToContinueReflow(nsIFrame *aFrame) 1.2770 +{ 1.2771 + NS_ASSERTION(mIsReflowing, "Must be in reflow when marking path dirty."); 1.2772 + NS_PRECONDITION(mCurrentReflowRoot, "Must have a current reflow root here"); 1.2773 + NS_ASSERTION(aFrame == mCurrentReflowRoot || 1.2774 + nsLayoutUtils::IsProperAncestorFrame(mCurrentReflowRoot, aFrame), 1.2775 + "Frame passed in is not the descendant of mCurrentReflowRoot"); 1.2776 + NS_ASSERTION(aFrame->GetStateBits() & NS_FRAME_IN_REFLOW, 1.2777 + "Frame passed in not in reflow?"); 1.2778 + 1.2779 + mFramesToDirty.PutEntry(aFrame); 1.2780 +} 1.2781 + 1.2782 +nsIScrollableFrame* 1.2783 +nsIPresShell::GetFrameToScrollAsScrollable( 1.2784 + nsIPresShell::ScrollDirection aDirection) 1.2785 +{ 1.2786 + nsIScrollableFrame* scrollFrame = nullptr; 1.2787 + 1.2788 + nsCOMPtr<nsIContent> focusedContent; 1.2789 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.2790 + if (fm && mDocument) { 1.2791 + nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(mDocument->GetWindow()); 1.2792 + 1.2793 + nsCOMPtr<nsIDOMElement> focusedElement; 1.2794 + fm->GetFocusedElementForWindow(window, false, nullptr, getter_AddRefs(focusedElement)); 1.2795 + focusedContent = do_QueryInterface(focusedElement); 1.2796 + } 1.2797 + if (!focusedContent && mSelection) { 1.2798 + nsISelection* domSelection = mSelection-> 1.2799 + GetSelection(nsISelectionController::SELECTION_NORMAL); 1.2800 + if (domSelection) { 1.2801 + nsCOMPtr<nsIDOMNode> focusedNode; 1.2802 + domSelection->GetFocusNode(getter_AddRefs(focusedNode)); 1.2803 + focusedContent = do_QueryInterface(focusedNode); 1.2804 + } 1.2805 + } 1.2806 + if (focusedContent) { 1.2807 + nsIFrame* startFrame = focusedContent->GetPrimaryFrame(); 1.2808 + if (startFrame) { 1.2809 + scrollFrame = startFrame->GetScrollTargetFrame(); 1.2810 + if (scrollFrame) { 1.2811 + startFrame = scrollFrame->GetScrolledFrame(); 1.2812 + } 1.2813 + if (aDirection == nsIPresShell::eEither) { 1.2814 + scrollFrame = 1.2815 + nsLayoutUtils::GetNearestScrollableFrame(startFrame); 1.2816 + } else { 1.2817 + scrollFrame = 1.2818 + nsLayoutUtils::GetNearestScrollableFrameForDirection(startFrame, 1.2819 + aDirection == eVertical ? nsLayoutUtils::eVertical : 1.2820 + nsLayoutUtils::eHorizontal); 1.2821 + } 1.2822 + } 1.2823 + } 1.2824 + if (!scrollFrame) { 1.2825 + scrollFrame = GetRootScrollFrameAsScrollable(); 1.2826 + } 1.2827 + return scrollFrame; 1.2828 +} 1.2829 + 1.2830 +void 1.2831 +PresShell::CancelAllPendingReflows() 1.2832 +{ 1.2833 + mDirtyRoots.Clear(); 1.2834 + 1.2835 + if (mReflowScheduled) { 1.2836 + GetPresContext()->RefreshDriver()->RemoveLayoutFlushObserver(this); 1.2837 + mReflowScheduled = false; 1.2838 + } 1.2839 + 1.2840 + ASSERT_REFLOW_SCHEDULED_STATE(); 1.2841 +} 1.2842 + 1.2843 +nsresult 1.2844 +PresShell::RecreateFramesFor(nsIContent* aContent) 1.2845 +{ 1.2846 + NS_ENSURE_TRUE(mPresContext, NS_ERROR_FAILURE); 1.2847 + if (!mDidInitialize) { 1.2848 + // Nothing to do here. In fact, if we proceed and aContent is the 1.2849 + // root we will crash. 1.2850 + return NS_OK; 1.2851 + } 1.2852 + 1.2853 + // Don't call RecreateFramesForContent since that is not exported and we want 1.2854 + // to keep the number of entrypoints down. 1.2855 + 1.2856 + NS_ASSERTION(mViewManager, "Should have view manager"); 1.2857 + 1.2858 + // Have to make sure that the content notifications are flushed before we 1.2859 + // start messing with the frame model; otherwise we can get content doubling. 1.2860 + mDocument->FlushPendingNotifications(Flush_ContentAndNotify); 1.2861 + 1.2862 + nsAutoScriptBlocker scriptBlocker; 1.2863 + 1.2864 + nsStyleChangeList changeList; 1.2865 + changeList.AppendChange(nullptr, aContent, nsChangeHint_ReconstructFrame); 1.2866 + 1.2867 + // Mark ourselves as not safe to flush while we're doing frame construction. 1.2868 + ++mChangeNestCount; 1.2869 + RestyleManager* restyleManager = mPresContext->RestyleManager(); 1.2870 + nsresult rv = restyleManager->ProcessRestyledFrames(changeList); 1.2871 + restyleManager->FlushOverflowChangedTracker(); 1.2872 + --mChangeNestCount; 1.2873 + 1.2874 + return rv; 1.2875 +} 1.2876 + 1.2877 +void 1.2878 +nsIPresShell::PostRecreateFramesFor(Element* aElement) 1.2879 +{ 1.2880 + mPresContext->RestyleManager()->PostRestyleEvent(aElement, nsRestyleHint(0), 1.2881 + nsChangeHint_ReconstructFrame); 1.2882 +} 1.2883 + 1.2884 +void 1.2885 +nsIPresShell::RestyleForAnimation(Element* aElement, nsRestyleHint aHint) 1.2886 +{ 1.2887 + mPresContext->RestyleManager()->PostAnimationRestyleEvent(aElement, aHint, 1.2888 + NS_STYLE_HINT_NONE); 1.2889 +} 1.2890 + 1.2891 +void 1.2892 +nsIPresShell::SetForwardingContainer(const WeakPtr<nsDocShell> &aContainer) 1.2893 +{ 1.2894 + mForwardingContainer = aContainer; 1.2895 +} 1.2896 + 1.2897 +void 1.2898 +PresShell::ClearFrameRefs(nsIFrame* aFrame) 1.2899 +{ 1.2900 + mPresContext->EventStateManager()->ClearFrameRefs(aFrame); 1.2901 + 1.2902 + nsWeakFrame* weakFrame = mWeakFrames; 1.2903 + while (weakFrame) { 1.2904 + nsWeakFrame* prev = weakFrame->GetPreviousWeakFrame(); 1.2905 + if (weakFrame->GetFrame() == aFrame) { 1.2906 + // This removes weakFrame from mWeakFrames. 1.2907 + weakFrame->Clear(this); 1.2908 + } 1.2909 + weakFrame = prev; 1.2910 + } 1.2911 +} 1.2912 + 1.2913 +already_AddRefed<nsRenderingContext> 1.2914 +PresShell::CreateReferenceRenderingContext() 1.2915 +{ 1.2916 + nsDeviceContext* devCtx = mPresContext->DeviceContext(); 1.2917 + nsRefPtr<nsRenderingContext> rc; 1.2918 + if (mPresContext->IsScreen()) { 1.2919 + rc = new nsRenderingContext(); 1.2920 + rc->Init(devCtx, gfxPlatform::GetPlatform()->ScreenReferenceSurface()); 1.2921 + } else { 1.2922 + rc = devCtx->CreateRenderingContext(); 1.2923 + } 1.2924 + 1.2925 + MOZ_ASSERT(rc, "shouldn't break promise to return non-null"); 1.2926 + return rc.forget(); 1.2927 +} 1.2928 + 1.2929 +nsresult 1.2930 +PresShell::GoToAnchor(const nsAString& aAnchorName, bool aScroll) 1.2931 +{ 1.2932 + if (!mDocument) { 1.2933 + return NS_ERROR_FAILURE; 1.2934 + } 1.2935 + 1.2936 + const Element *root = mDocument->GetRootElement(); 1.2937 + if (root && root->IsSVG(nsGkAtoms::svg)) { 1.2938 + // We need to execute this even if there is an empty anchor name 1.2939 + // so that any existing SVG fragment identifier effect is removed 1.2940 + if (SVGFragmentIdentifier::ProcessFragmentIdentifier(mDocument, aAnchorName)) { 1.2941 + return NS_OK; 1.2942 + } 1.2943 + } 1.2944 + 1.2945 + // Hold a reference to the ESM in case event dispatch tears us down. 1.2946 + nsRefPtr<EventStateManager> esm = mPresContext->EventStateManager(); 1.2947 + 1.2948 + if (aAnchorName.IsEmpty()) { 1.2949 + NS_ASSERTION(!aScroll, "can't scroll to empty anchor name"); 1.2950 + esm->SetContentState(nullptr, NS_EVENT_STATE_URLTARGET); 1.2951 + return NS_OK; 1.2952 + } 1.2953 + 1.2954 + nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument); 1.2955 + nsresult rv = NS_OK; 1.2956 + nsCOMPtr<nsIContent> content; 1.2957 + 1.2958 + // Search for an element with a matching "id" attribute 1.2959 + if (mDocument) { 1.2960 + content = mDocument->GetElementById(aAnchorName); 1.2961 + } 1.2962 + 1.2963 + // Search for an anchor element with a matching "name" attribute 1.2964 + if (!content && htmlDoc) { 1.2965 + nsCOMPtr<nsIDOMNodeList> list; 1.2966 + // Find a matching list of named nodes 1.2967 + rv = htmlDoc->GetElementsByName(aAnchorName, getter_AddRefs(list)); 1.2968 + if (NS_SUCCEEDED(rv) && list) { 1.2969 + uint32_t i; 1.2970 + // Loop through the named nodes looking for the first anchor 1.2971 + for (i = 0; true; i++) { 1.2972 + nsCOMPtr<nsIDOMNode> node; 1.2973 + rv = list->Item(i, getter_AddRefs(node)); 1.2974 + if (!node) { // End of list 1.2975 + break; 1.2976 + } 1.2977 + // Ensure it's an anchor element 1.2978 + content = do_QueryInterface(node); 1.2979 + if (content) { 1.2980 + if (content->Tag() == nsGkAtoms::a && content->IsHTML()) { 1.2981 + break; 1.2982 + } 1.2983 + content = nullptr; 1.2984 + } 1.2985 + } 1.2986 + } 1.2987 + } 1.2988 + 1.2989 + // Search for anchor in the HTML namespace with a matching name 1.2990 + if (!content && !htmlDoc) 1.2991 + { 1.2992 + nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(mDocument); 1.2993 + nsCOMPtr<nsIDOMNodeList> list; 1.2994 + NS_NAMED_LITERAL_STRING(nameSpace, "http://www.w3.org/1999/xhtml"); 1.2995 + // Get the list of anchor elements 1.2996 + rv = doc->GetElementsByTagNameNS(nameSpace, NS_LITERAL_STRING("a"), getter_AddRefs(list)); 1.2997 + if (NS_SUCCEEDED(rv) && list) { 1.2998 + uint32_t i; 1.2999 + // Loop through the named nodes looking for the first anchor 1.3000 + for (i = 0; true; i++) { 1.3001 + nsCOMPtr<nsIDOMNode> node; 1.3002 + rv = list->Item(i, getter_AddRefs(node)); 1.3003 + if (!node) { // End of list 1.3004 + break; 1.3005 + } 1.3006 + // Compare the name attribute 1.3007 + nsCOMPtr<nsIDOMElement> element = do_QueryInterface(node); 1.3008 + nsAutoString value; 1.3009 + if (element && NS_SUCCEEDED(element->GetAttribute(NS_LITERAL_STRING("name"), value))) { 1.3010 + if (value.Equals(aAnchorName)) { 1.3011 + content = do_QueryInterface(element); 1.3012 + break; 1.3013 + } 1.3014 + } 1.3015 + } 1.3016 + } 1.3017 + } 1.3018 + 1.3019 + esm->SetContentState(content, NS_EVENT_STATE_URLTARGET); 1.3020 + 1.3021 +#ifdef ACCESSIBILITY 1.3022 + nsIContent *anchorTarget = content; 1.3023 +#endif 1.3024 + 1.3025 + nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable(); 1.3026 + if (rootScroll && rootScroll->DidHistoryRestore()) { 1.3027 + // Scroll position restored from history trumps scrolling to anchor. 1.3028 + aScroll = false; 1.3029 + rootScroll->ClearDidHistoryRestore(); 1.3030 + } 1.3031 + 1.3032 + if (content) { 1.3033 + if (aScroll) { 1.3034 + rv = ScrollContentIntoView(content, 1.3035 + ScrollAxis(SCROLL_TOP, SCROLL_ALWAYS), 1.3036 + ScrollAxis(), 1.3037 + ANCHOR_SCROLL_FLAGS); 1.3038 + NS_ENSURE_SUCCESS(rv, rv); 1.3039 + 1.3040 + nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable(); 1.3041 + if (rootScroll) { 1.3042 + mLastAnchorScrolledTo = content; 1.3043 + mLastAnchorScrollPositionY = rootScroll->GetScrollPosition().y; 1.3044 + } 1.3045 + } 1.3046 + 1.3047 + // Should we select the target? This action is controlled by a 1.3048 + // preference: the default is to not select. 1.3049 + bool selectAnchor = Preferences::GetBool("layout.selectanchor"); 1.3050 + 1.3051 + // Even if select anchor pref is false, we must still move the 1.3052 + // caret there. That way tabbing will start from the new 1.3053 + // location 1.3054 + nsRefPtr<nsIDOMRange> jumpToRange = new nsRange(mDocument); 1.3055 + while (content && content->GetFirstChild()) { 1.3056 + content = content->GetFirstChild(); 1.3057 + } 1.3058 + nsCOMPtr<nsIDOMNode> node(do_QueryInterface(content)); 1.3059 + NS_ASSERTION(node, "No nsIDOMNode for descendant of anchor"); 1.3060 + jumpToRange->SelectNodeContents(node); 1.3061 + // Select the anchor 1.3062 + nsISelection* sel = mSelection-> 1.3063 + GetSelection(nsISelectionController::SELECTION_NORMAL); 1.3064 + if (sel) { 1.3065 + sel->RemoveAllRanges(); 1.3066 + sel->AddRange(jumpToRange); 1.3067 + if (!selectAnchor) { 1.3068 + // Use a caret (collapsed selection) at the start of the anchor 1.3069 + sel->CollapseToStart(); 1.3070 + } 1.3071 + } 1.3072 + // Selection is at anchor. 1.3073 + // Now focus the document itself if focus is on an element within it. 1.3074 + nsPIDOMWindow *win = mDocument->GetWindow(); 1.3075 + 1.3076 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.3077 + if (fm && win) { 1.3078 + nsCOMPtr<nsIDOMWindow> focusedWindow; 1.3079 + fm->GetFocusedWindow(getter_AddRefs(focusedWindow)); 1.3080 + if (SameCOMIdentity(win, focusedWindow)) { 1.3081 + fm->ClearFocus(focusedWindow); 1.3082 + } 1.3083 + } 1.3084 + 1.3085 + // If the target is an animation element, activate the animation 1.3086 + if (content->IsNodeOfType(nsINode::eANIMATION)) { 1.3087 + SVGContentUtils::ActivateByHyperlink(content.get()); 1.3088 + } 1.3089 + } else { 1.3090 + rv = NS_ERROR_FAILURE; 1.3091 + NS_NAMED_LITERAL_STRING(top, "top"); 1.3092 + if (nsContentUtils::EqualsIgnoreASCIICase(aAnchorName, top)) { 1.3093 + // Scroll to the top/left if aAnchorName is "top" and there is no element 1.3094 + // with such a name or id. 1.3095 + rv = NS_OK; 1.3096 + nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable(); 1.3097 + // Check |aScroll| after setting |rv| so we set |rv| to the same 1.3098 + // thing whether or not |aScroll| is true. 1.3099 + if (aScroll && sf) { 1.3100 + // Scroll to the top of the page 1.3101 + sf->ScrollTo(nsPoint(0, 0), nsIScrollableFrame::INSTANT); 1.3102 + } 1.3103 + } 1.3104 + } 1.3105 + 1.3106 +#ifdef ACCESSIBILITY 1.3107 + if (anchorTarget) { 1.3108 + nsAccessibilityService* accService = AccService(); 1.3109 + if (accService) 1.3110 + accService->NotifyOfAnchorJumpTo(anchorTarget); 1.3111 + } 1.3112 +#endif 1.3113 + 1.3114 + return rv; 1.3115 +} 1.3116 + 1.3117 +nsresult 1.3118 +PresShell::ScrollToAnchor() 1.3119 +{ 1.3120 + if (!mLastAnchorScrolledTo) { 1.3121 + return NS_OK; 1.3122 + } 1.3123 + NS_ASSERTION(mDidInitialize, "should have done initial reflow by now"); 1.3124 + 1.3125 + nsIScrollableFrame* rootScroll = GetRootScrollFrameAsScrollable(); 1.3126 + if (!rootScroll || 1.3127 + mLastAnchorScrollPositionY != rootScroll->GetScrollPosition().y) { 1.3128 + return NS_OK; 1.3129 + } 1.3130 + nsresult rv = ScrollContentIntoView(mLastAnchorScrolledTo, 1.3131 + ScrollAxis(SCROLL_TOP, SCROLL_ALWAYS), 1.3132 + ScrollAxis(), 1.3133 + ANCHOR_SCROLL_FLAGS); 1.3134 + mLastAnchorScrolledTo = nullptr; 1.3135 + return rv; 1.3136 +} 1.3137 + 1.3138 +/* 1.3139 + * Helper (per-continuation) for ScrollContentIntoView. 1.3140 + * 1.3141 + * @param aContainerFrame [in] the frame which aRect is relative to 1.3142 + * @param aFrame [in] Frame whose bounds should be unioned 1.3143 + * @param aUseWholeLineHeightForInlines [in] if true, then for inline frames 1.3144 + * we should include the top of the line in the added rectangle 1.3145 + * @param aRect [inout] rect into which its bounds should be unioned 1.3146 + * @param aHaveRect [inout] whether aRect contains data yet 1.3147 + * @param aPrevBlock [inout] the block aLines is a line iterator for 1.3148 + * @param aLines [inout] the line iterator we're using 1.3149 + * @param aCurLine [inout] the line to start looking from in this iterator 1.3150 + */ 1.3151 +static void 1.3152 +AccumulateFrameBounds(nsIFrame* aContainerFrame, 1.3153 + nsIFrame* aFrame, 1.3154 + bool aUseWholeLineHeightForInlines, 1.3155 + nsRect& aRect, 1.3156 + bool& aHaveRect, 1.3157 + nsIFrame*& aPrevBlock, 1.3158 + nsAutoLineIterator& aLines, 1.3159 + int32_t& aCurLine) 1.3160 +{ 1.3161 + nsIFrame* frame = aFrame; 1.3162 + nsRect frameBounds = nsRect(nsPoint(0, 0), aFrame->GetSize()); 1.3163 + 1.3164 + // If this is an inline frame and either the bounds height is 0 (quirks 1.3165 + // layout model) or aUseWholeLineHeightForInlines is set, we need to 1.3166 + // change the top of the bounds to include the whole line. 1.3167 + if (frameBounds.height == 0 || aUseWholeLineHeightForInlines) { 1.3168 + nsIFrame *prevFrame = aFrame; 1.3169 + nsIFrame *f = aFrame; 1.3170 + 1.3171 + while (f && f->IsFrameOfType(nsIFrame::eLineParticipant) && 1.3172 + !f->IsTransformed() && !f->IsPositioned()) { 1.3173 + prevFrame = f; 1.3174 + f = prevFrame->GetParent(); 1.3175 + } 1.3176 + 1.3177 + if (f != aFrame && 1.3178 + f && 1.3179 + f->GetType() == nsGkAtoms::blockFrame) { 1.3180 + // find the line containing aFrame and increase the top of |offset|. 1.3181 + if (f != aPrevBlock) { 1.3182 + aLines = f->GetLineIterator(); 1.3183 + aPrevBlock = f; 1.3184 + aCurLine = 0; 1.3185 + } 1.3186 + if (aLines) { 1.3187 + int32_t index = aLines->FindLineContaining(prevFrame, aCurLine); 1.3188 + if (index >= 0) { 1.3189 + aCurLine = index; 1.3190 + nsIFrame *trash1; 1.3191 + int32_t trash2; 1.3192 + nsRect lineBounds; 1.3193 + uint32_t trash3; 1.3194 + 1.3195 + if (NS_SUCCEEDED(aLines->GetLine(index, &trash1, &trash2, 1.3196 + lineBounds, &trash3))) { 1.3197 + frameBounds += frame->GetOffsetTo(f); 1.3198 + frame = f; 1.3199 + if (lineBounds.y < frameBounds.y) { 1.3200 + frameBounds.height = frameBounds.YMost() - lineBounds.y; 1.3201 + frameBounds.y = lineBounds.y; 1.3202 + } 1.3203 + } 1.3204 + } 1.3205 + } 1.3206 + } 1.3207 + } 1.3208 + 1.3209 + nsRect transformedBounds = nsLayoutUtils::TransformFrameRectToAncestor(frame, 1.3210 + frameBounds, aContainerFrame); 1.3211 + 1.3212 + if (aHaveRect) { 1.3213 + // We can't use nsRect::UnionRect since it drops empty rects on 1.3214 + // the floor, and we need to include them. (Thus we need 1.3215 + // aHaveRect to know when to drop the initial value on the floor.) 1.3216 + aRect.UnionRectEdges(aRect, transformedBounds); 1.3217 + } else { 1.3218 + aHaveRect = true; 1.3219 + aRect = transformedBounds; 1.3220 + } 1.3221 +} 1.3222 + 1.3223 +static bool 1.3224 +ComputeNeedToScroll(nsIPresShell::WhenToScroll aWhenToScroll, 1.3225 + nscoord aLineSize, 1.3226 + nscoord aRectMin, 1.3227 + nscoord aRectMax, 1.3228 + nscoord aViewMin, 1.3229 + nscoord aViewMax) { 1.3230 + // See how the rect should be positioned vertically 1.3231 + if (nsIPresShell::SCROLL_ALWAYS == aWhenToScroll) { 1.3232 + // The caller wants the frame as visible as possible 1.3233 + return true; 1.3234 + } else if (nsIPresShell::SCROLL_IF_NOT_VISIBLE == aWhenToScroll) { 1.3235 + // Scroll only if no part of the frame is visible in this view 1.3236 + return aRectMax - aLineSize <= aViewMin || 1.3237 + aRectMin + aLineSize >= aViewMax; 1.3238 + } else if (nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE == aWhenToScroll) { 1.3239 + // Scroll only if part of the frame is hidden and more can fit in view 1.3240 + return !(aRectMin >= aViewMin && aRectMax <= aViewMax) && 1.3241 + std::min(aViewMax, aRectMax) - std::max(aRectMin, aViewMin) < aViewMax - aViewMin; 1.3242 + } 1.3243 + return false; 1.3244 +} 1.3245 + 1.3246 +static nscoord 1.3247 +ComputeWhereToScroll(int16_t aWhereToScroll, 1.3248 + nscoord aOriginalCoord, 1.3249 + nscoord aRectMin, 1.3250 + nscoord aRectMax, 1.3251 + nscoord aViewMin, 1.3252 + nscoord aViewMax, 1.3253 + nscoord* aRangeMin, 1.3254 + nscoord* aRangeMax) { 1.3255 + nscoord resultCoord = aOriginalCoord; 1.3256 + // Allow the scroll operation to land anywhere that 1.3257 + // makes the whole rectangle visible. 1.3258 + if (nsIPresShell::SCROLL_MINIMUM == aWhereToScroll) { 1.3259 + if (aRectMin < aViewMin) { 1.3260 + // Scroll up so the frame's top edge is visible 1.3261 + resultCoord = aRectMin; 1.3262 + } else if (aRectMax > aViewMax) { 1.3263 + // Scroll down so the frame's bottom edge is visible. Make sure the 1.3264 + // frame's top edge is still visible 1.3265 + resultCoord = aOriginalCoord + aRectMax - aViewMax; 1.3266 + if (resultCoord > aRectMin) { 1.3267 + resultCoord = aRectMin; 1.3268 + } 1.3269 + } 1.3270 + } else { 1.3271 + nscoord frameAlignCoord = 1.3272 + NSToCoordRound(aRectMin + (aRectMax - aRectMin) * (aWhereToScroll / 100.0f)); 1.3273 + resultCoord = NSToCoordRound(frameAlignCoord - (aViewMax - aViewMin) * ( 1.3274 + aWhereToScroll / 100.0f)); 1.3275 + } 1.3276 + nscoord scrollPortLength = aViewMax - aViewMin; 1.3277 + // Force the scroll range to extend to include resultCoord. 1.3278 + *aRangeMin = std::min(resultCoord, aRectMax - scrollPortLength); 1.3279 + *aRangeMax = std::max(resultCoord, aRectMin); 1.3280 + return resultCoord; 1.3281 +} 1.3282 + 1.3283 +/** 1.3284 + * This function takes a scrollable frame, a rect in the coordinate system 1.3285 + * of the scrolled frame, and a desired percentage-based scroll 1.3286 + * position and attempts to scroll the rect to that position in the 1.3287 + * scrollport. 1.3288 + * 1.3289 + * This needs to work even if aRect has a width or height of zero. 1.3290 + */ 1.3291 +static void ScrollToShowRect(nsIFrame* aFrame, 1.3292 + nsIScrollableFrame* aFrameAsScrollable, 1.3293 + const nsRect& aRect, 1.3294 + nsIPresShell::ScrollAxis aVertical, 1.3295 + nsIPresShell::ScrollAxis aHorizontal, 1.3296 + uint32_t aFlags) 1.3297 +{ 1.3298 + nsPoint scrollPt = aFrameAsScrollable->GetScrollPosition(); 1.3299 + nsRect visibleRect(scrollPt, 1.3300 + aFrameAsScrollable->GetScrollPositionClampingScrollPortSize()); 1.3301 + 1.3302 + // If this is the root scroll frame, make sure to take into account the 1.3303 + // content document fixed position margins. When set, these indicate that 1.3304 + // chrome is obscuring the viewport. 1.3305 + nsRect targetRect(aRect); 1.3306 + nsIPresShell *presShell = aFrame->PresContext()->PresShell(); 1.3307 + if (aFrameAsScrollable == presShell->GetRootScrollFrameAsScrollable()) { 1.3308 + targetRect.Inflate(presShell->GetContentDocumentFixedPositionMargins()); 1.3309 + } 1.3310 + 1.3311 + nsSize lineSize; 1.3312 + // Don't call GetLineScrollAmount unless we actually need it. Not only 1.3313 + // does this save time, but it's not safe to call GetLineScrollAmount 1.3314 + // during reflow (because it depends on font size inflation and doesn't 1.3315 + // use the in-reflow-safe font-size inflation path). If we did call it, 1.3316 + // it would assert and possible give the wrong result. 1.3317 + if (aVertical.mWhenToScroll == nsIPresShell::SCROLL_IF_NOT_VISIBLE || 1.3318 + aHorizontal.mWhenToScroll == nsIPresShell::SCROLL_IF_NOT_VISIBLE) { 1.3319 + lineSize = aFrameAsScrollable->GetLineScrollAmount(); 1.3320 + } 1.3321 + ScrollbarStyles ss = aFrameAsScrollable->GetScrollbarStyles(); 1.3322 + nsRect allowedRange(scrollPt, nsSize(0, 0)); 1.3323 + bool needToScroll = false; 1.3324 + uint32_t directions = aFrameAsScrollable->GetPerceivedScrollingDirections(); 1.3325 + 1.3326 + if (((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) || 1.3327 + ss.mVertical != NS_STYLE_OVERFLOW_HIDDEN) && 1.3328 + (!aVertical.mOnlyIfPerceivedScrollableDirection || 1.3329 + (directions & nsIScrollableFrame::VERTICAL))) { 1.3330 + 1.3331 + if (ComputeNeedToScroll(aVertical.mWhenToScroll, 1.3332 + lineSize.height, 1.3333 + targetRect.y, 1.3334 + targetRect.YMost(), 1.3335 + visibleRect.y, 1.3336 + visibleRect.YMost())) { 1.3337 + nscoord maxHeight; 1.3338 + scrollPt.y = ComputeWhereToScroll(aVertical.mWhereToScroll, 1.3339 + scrollPt.y, 1.3340 + targetRect.y, 1.3341 + targetRect.YMost(), 1.3342 + visibleRect.y, 1.3343 + visibleRect.YMost(), 1.3344 + &allowedRange.y, &maxHeight); 1.3345 + allowedRange.height = maxHeight - allowedRange.y; 1.3346 + needToScroll = true; 1.3347 + } 1.3348 + } 1.3349 + 1.3350 + if (((aFlags & nsIPresShell::SCROLL_OVERFLOW_HIDDEN) || 1.3351 + ss.mHorizontal != NS_STYLE_OVERFLOW_HIDDEN) && 1.3352 + (!aHorizontal.mOnlyIfPerceivedScrollableDirection || 1.3353 + (directions & nsIScrollableFrame::HORIZONTAL))) { 1.3354 + 1.3355 + if (ComputeNeedToScroll(aHorizontal.mWhenToScroll, 1.3356 + lineSize.width, 1.3357 + targetRect.x, 1.3358 + targetRect.XMost(), 1.3359 + visibleRect.x, 1.3360 + visibleRect.XMost())) { 1.3361 + nscoord maxWidth; 1.3362 + scrollPt.x = ComputeWhereToScroll(aHorizontal.mWhereToScroll, 1.3363 + scrollPt.x, 1.3364 + targetRect.x, 1.3365 + targetRect.XMost(), 1.3366 + visibleRect.x, 1.3367 + visibleRect.XMost(), 1.3368 + &allowedRange.x, &maxWidth); 1.3369 + allowedRange.width = maxWidth - allowedRange.x; 1.3370 + needToScroll = true; 1.3371 + } 1.3372 + } 1.3373 + 1.3374 + // If we don't need to scroll, then don't try since it might cancel 1.3375 + // a current smooth scroll operation. 1.3376 + if (needToScroll) { 1.3377 + aFrameAsScrollable->ScrollTo(scrollPt, nsIScrollableFrame::INSTANT, &allowedRange); 1.3378 + } 1.3379 +} 1.3380 + 1.3381 +nsresult 1.3382 +PresShell::ScrollContentIntoView(nsIContent* aContent, 1.3383 + nsIPresShell::ScrollAxis aVertical, 1.3384 + nsIPresShell::ScrollAxis aHorizontal, 1.3385 + uint32_t aFlags) 1.3386 +{ 1.3387 + NS_ENSURE_TRUE(aContent, NS_ERROR_NULL_POINTER); 1.3388 + nsCOMPtr<nsIDocument> currentDoc = aContent->GetCurrentDoc(); 1.3389 + NS_ENSURE_STATE(currentDoc); 1.3390 + 1.3391 + NS_ASSERTION(mDidInitialize, "should have done initial reflow by now"); 1.3392 + 1.3393 + if (mContentToScrollTo) { 1.3394 + mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling); 1.3395 + } 1.3396 + mContentToScrollTo = aContent; 1.3397 + ScrollIntoViewData* data = new ScrollIntoViewData(); 1.3398 + data->mContentScrollVAxis = aVertical; 1.3399 + data->mContentScrollHAxis = aHorizontal; 1.3400 + data->mContentToScrollToFlags = aFlags; 1.3401 + if (NS_FAILED(mContentToScrollTo->SetProperty(nsGkAtoms::scrolling, data, 1.3402 + nsINode::DeleteProperty<PresShell::ScrollIntoViewData>))) { 1.3403 + mContentToScrollTo = nullptr; 1.3404 + } 1.3405 + 1.3406 + // Flush layout and attempt to scroll in the process. 1.3407 + currentDoc->SetNeedLayoutFlush(); 1.3408 + currentDoc->FlushPendingNotifications(Flush_InterruptibleLayout); 1.3409 + 1.3410 + // If mContentToScrollTo is non-null, that means we interrupted the reflow 1.3411 + // (or suppressed it altogether because we're suppressing interruptible 1.3412 + // flushes right now) and won't necessarily get the position correct, but do 1.3413 + // a best-effort scroll here. The other option would be to do this inside 1.3414 + // FlushPendingNotifications, but I'm not sure the repeated scrolling that 1.3415 + // could trigger if reflows keep getting interrupted would be more desirable 1.3416 + // than a single best-effort scroll followed by one final scroll on the first 1.3417 + // completed reflow. 1.3418 + if (mContentToScrollTo) { 1.3419 + DoScrollContentIntoView(); 1.3420 + } 1.3421 + return NS_OK; 1.3422 +} 1.3423 + 1.3424 +void 1.3425 +PresShell::DoScrollContentIntoView() 1.3426 +{ 1.3427 + NS_ASSERTION(mDidInitialize, "should have done initial reflow by now"); 1.3428 + 1.3429 + nsIFrame* frame = mContentToScrollTo->GetPrimaryFrame(); 1.3430 + if (!frame) { 1.3431 + mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling); 1.3432 + mContentToScrollTo = nullptr; 1.3433 + return; 1.3434 + } 1.3435 + 1.3436 + if (frame->GetStateBits() & NS_FRAME_FIRST_REFLOW) { 1.3437 + // The reflow flush before this scroll got interrupted, and this frame's 1.3438 + // coords and size are all zero, and it has no content showing anyway. 1.3439 + // Don't bother scrolling to it. We'll try again when we finish up layout. 1.3440 + return; 1.3441 + } 1.3442 + 1.3443 + // Make sure we skip 'frame' ... if it's scrollable, we should use its 1.3444 + // scrollable ancestor as the container. 1.3445 + nsIFrame* container = 1.3446 + nsLayoutUtils::GetClosestFrameOfType(frame->GetParent(), nsGkAtoms::scrollFrame); 1.3447 + if (!container) { 1.3448 + // nothing can be scrolled 1.3449 + return; 1.3450 + } 1.3451 + 1.3452 + ScrollIntoViewData* data = static_cast<ScrollIntoViewData*>( 1.3453 + mContentToScrollTo->GetProperty(nsGkAtoms::scrolling)); 1.3454 + if (MOZ_UNLIKELY(!data)) { 1.3455 + mContentToScrollTo = nullptr; 1.3456 + return; 1.3457 + } 1.3458 + 1.3459 + // This is a two-step process. 1.3460 + // Step 1: Find the bounds of the rect we want to scroll into view. For 1.3461 + // example, for an inline frame we may want to scroll in the whole 1.3462 + // line, or we may want to scroll multiple lines into view. 1.3463 + // Step 2: Walk container frame and its ancestors and scroll them 1.3464 + // appropriately. 1.3465 + // frameBounds is relative to container. We're assuming 1.3466 + // that scrollframes don't split so every continuation of frame will 1.3467 + // be a descendant of container. (Things would still mostly work 1.3468 + // even if that assumption was false.) 1.3469 + nsRect frameBounds; 1.3470 + bool haveRect = false; 1.3471 + bool useWholeLineHeightForInlines = 1.3472 + data->mContentScrollVAxis.mWhenToScroll != nsIPresShell::SCROLL_IF_NOT_FULLY_VISIBLE; 1.3473 + // Reuse the same line iterator across calls to AccumulateFrameBounds. We set 1.3474 + // it every time we detect a new block (stored in prevBlock). 1.3475 + nsIFrame* prevBlock = nullptr; 1.3476 + nsAutoLineIterator lines; 1.3477 + // The last line we found a continuation on in |lines|. We assume that later 1.3478 + // continuations cannot come on earlier lines. 1.3479 + int32_t curLine = 0; 1.3480 + do { 1.3481 + AccumulateFrameBounds(container, frame, useWholeLineHeightForInlines, 1.3482 + frameBounds, haveRect, prevBlock, lines, curLine); 1.3483 + } while ((frame = frame->GetNextContinuation())); 1.3484 + 1.3485 + ScrollFrameRectIntoView(container, frameBounds, data->mContentScrollVAxis, 1.3486 + data->mContentScrollHAxis, 1.3487 + data->mContentToScrollToFlags); 1.3488 +} 1.3489 + 1.3490 +bool 1.3491 +PresShell::ScrollFrameRectIntoView(nsIFrame* aFrame, 1.3492 + const nsRect& aRect, 1.3493 + nsIPresShell::ScrollAxis aVertical, 1.3494 + nsIPresShell::ScrollAxis aHorizontal, 1.3495 + uint32_t aFlags) 1.3496 +{ 1.3497 + bool didScroll = false; 1.3498 + // This function needs to work even if rect has a width or height of 0. 1.3499 + nsRect rect = aRect; 1.3500 + nsIFrame* container = aFrame; 1.3501 + // Walk up the frame hierarchy scrolling the rect into view and 1.3502 + // keeping rect relative to container 1.3503 + do { 1.3504 + nsIScrollableFrame* sf = do_QueryFrame(container); 1.3505 + if (sf) { 1.3506 + nsPoint oldPosition = sf->GetScrollPosition(); 1.3507 + nsRect targetRect = rect; 1.3508 + if (container->StyleDisplay()->mOverflowClipBox == 1.3509 + NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX) { 1.3510 + nsMargin padding = container->GetUsedPadding(); 1.3511 + targetRect.Inflate(padding); 1.3512 + } 1.3513 + ScrollToShowRect(container, sf, targetRect - sf->GetScrolledFrame()->GetPosition(), 1.3514 + aVertical, aHorizontal, aFlags); 1.3515 + nsPoint newPosition = sf->GetScrollPosition(); 1.3516 + // If the scroll position increased, that means our content moved up, 1.3517 + // so our rect's offset should decrease 1.3518 + rect += oldPosition - newPosition; 1.3519 + 1.3520 + if (oldPosition != newPosition) { 1.3521 + didScroll = true; 1.3522 + } 1.3523 + 1.3524 + // only scroll one container when this flag is set 1.3525 + if (aFlags & nsIPresShell::SCROLL_FIRST_ANCESTOR_ONLY) { 1.3526 + break; 1.3527 + } 1.3528 + } 1.3529 + nsIFrame* parent; 1.3530 + if (container->IsTransformed()) { 1.3531 + container->GetTransformMatrix(nullptr, &parent); 1.3532 + rect = nsLayoutUtils::TransformFrameRectToAncestor(container, rect, parent); 1.3533 + } else { 1.3534 + rect += container->GetPosition(); 1.3535 + parent = container->GetParent(); 1.3536 + } 1.3537 + if (!parent && !(aFlags & nsIPresShell::SCROLL_NO_PARENT_FRAMES)) { 1.3538 + nsPoint extraOffset(0,0); 1.3539 + parent = nsLayoutUtils::GetCrossDocParentFrame(container, &extraOffset); 1.3540 + if (parent) { 1.3541 + int32_t APD = container->PresContext()->AppUnitsPerDevPixel(); 1.3542 + int32_t parentAPD = parent->PresContext()->AppUnitsPerDevPixel(); 1.3543 + rect = rect.ConvertAppUnitsRoundOut(APD, parentAPD); 1.3544 + rect += extraOffset; 1.3545 + } 1.3546 + } 1.3547 + container = parent; 1.3548 + } while (container); 1.3549 + 1.3550 + return didScroll; 1.3551 +} 1.3552 + 1.3553 +nsRectVisibility 1.3554 +PresShell::GetRectVisibility(nsIFrame* aFrame, 1.3555 + const nsRect &aRect, 1.3556 + nscoord aMinTwips) const 1.3557 +{ 1.3558 + NS_ASSERTION(aFrame->PresContext() == GetPresContext(), 1.3559 + "prescontext mismatch?"); 1.3560 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.3561 + NS_ASSERTION(rootFrame, 1.3562 + "How can someone have a frame for this presshell when there's no root?"); 1.3563 + nsIScrollableFrame* sf = GetRootScrollFrameAsScrollable(); 1.3564 + nsRect scrollPortRect; 1.3565 + if (sf) { 1.3566 + scrollPortRect = sf->GetScrollPortRect(); 1.3567 + nsIFrame* f = do_QueryFrame(sf); 1.3568 + scrollPortRect += f->GetOffsetTo(rootFrame); 1.3569 + } else { 1.3570 + scrollPortRect = nsRect(nsPoint(0,0), rootFrame->GetSize()); 1.3571 + } 1.3572 + 1.3573 + nsRect r = aRect + aFrame->GetOffsetTo(rootFrame); 1.3574 + // If aRect is entirely visible then we don't need to ensure that 1.3575 + // at least aMinTwips of it is visible 1.3576 + if (scrollPortRect.Contains(r)) 1.3577 + return nsRectVisibility_kVisible; 1.3578 + 1.3579 + nsRect insetRect = scrollPortRect; 1.3580 + insetRect.Deflate(aMinTwips, aMinTwips); 1.3581 + if (r.YMost() <= insetRect.y) 1.3582 + return nsRectVisibility_kAboveViewport; 1.3583 + if (r.y >= insetRect.YMost()) 1.3584 + return nsRectVisibility_kBelowViewport; 1.3585 + if (r.XMost() <= insetRect.x) 1.3586 + return nsRectVisibility_kLeftOfViewport; 1.3587 + if (r.x >= insetRect.XMost()) 1.3588 + return nsRectVisibility_kRightOfViewport; 1.3589 + 1.3590 + return nsRectVisibility_kVisible; 1.3591 +} 1.3592 + 1.3593 +class PaintTimerCallBack MOZ_FINAL : public nsITimerCallback 1.3594 +{ 1.3595 +public: 1.3596 + PaintTimerCallBack(PresShell* aShell) : mShell(aShell) {} 1.3597 + 1.3598 + NS_DECL_ISUPPORTS 1.3599 + 1.3600 + NS_IMETHODIMP Notify(nsITimer* aTimer) MOZ_FINAL 1.3601 + { 1.3602 + mShell->SetNextPaintCompressed(); 1.3603 + mShell->AddInvalidateHiddenPresShellObserver(mShell->GetPresContext()->RefreshDriver()); 1.3604 + mShell->ScheduleViewManagerFlush(); 1.3605 + return NS_OK; 1.3606 + } 1.3607 + 1.3608 +private: 1.3609 + PresShell* mShell; 1.3610 +}; 1.3611 + 1.3612 +NS_IMPL_ISUPPORTS(PaintTimerCallBack, nsITimerCallback) 1.3613 + 1.3614 +void 1.3615 +PresShell::ScheduleViewManagerFlush(PaintType aType) 1.3616 +{ 1.3617 + if (aType == PAINT_DELAYED_COMPRESS) { 1.3618 + // Delay paint for 1 second. 1.3619 + static const uint32_t kPaintDelayPeriod = 1000; 1.3620 + if (!mDelayedPaintTimer) { 1.3621 + mDelayedPaintTimer = do_CreateInstance(NS_TIMER_CONTRACTID); 1.3622 + nsRefPtr<PaintTimerCallBack> cb = new PaintTimerCallBack(this); 1.3623 + mDelayedPaintTimer->InitWithCallback(cb, kPaintDelayPeriod, nsITimer::TYPE_ONE_SHOT); 1.3624 + } 1.3625 + return; 1.3626 + } 1.3627 + 1.3628 + nsPresContext* presContext = GetPresContext(); 1.3629 + if (presContext) { 1.3630 + presContext->RefreshDriver()->ScheduleViewManagerFlush(); 1.3631 + } 1.3632 + if (mDocument) { 1.3633 + mDocument->SetNeedLayoutFlush(); 1.3634 + } 1.3635 +} 1.3636 + 1.3637 +void 1.3638 +PresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent, 1.3639 + bool aFlushOnHoverChange) 1.3640 +{ 1.3641 + RestyleManager* restyleManager = mPresContext->RestyleManager(); 1.3642 + uint32_t hoverGenerationBefore = restyleManager->GetHoverGeneration(); 1.3643 + nsEventStatus status; 1.3644 + nsView* targetView = nsView::GetViewFor(aEvent->widget); 1.3645 + if (!targetView) 1.3646 + return; 1.3647 + targetView->GetViewManager()->DispatchEvent(aEvent, targetView, &status); 1.3648 + if (MOZ_UNLIKELY(mIsDestroying)) { 1.3649 + return; 1.3650 + } 1.3651 + if (aFlushOnHoverChange && 1.3652 + hoverGenerationBefore != restyleManager->GetHoverGeneration()) { 1.3653 + // Flush so that the resulting reflow happens now so that our caller 1.3654 + // can suppress any synthesized mouse moves caused by that reflow. 1.3655 + FlushPendingNotifications(Flush_Layout); 1.3656 + } 1.3657 +} 1.3658 + 1.3659 +void 1.3660 +PresShell::ClearMouseCaptureOnView(nsView* aView) 1.3661 +{ 1.3662 + if (gCaptureInfo.mContent) { 1.3663 + if (aView) { 1.3664 + // if a view was specified, ensure that the captured content is within 1.3665 + // this view. 1.3666 + nsIFrame* frame = gCaptureInfo.mContent->GetPrimaryFrame(); 1.3667 + if (frame) { 1.3668 + nsView* view = frame->GetClosestView(); 1.3669 + // if there is no view, capturing won't be handled any more, so 1.3670 + // just release the capture. 1.3671 + if (view) { 1.3672 + do { 1.3673 + if (view == aView) { 1.3674 + NS_RELEASE(gCaptureInfo.mContent); 1.3675 + // the view containing the captured content likely disappeared so 1.3676 + // disable capture for now. 1.3677 + gCaptureInfo.mAllowed = false; 1.3678 + break; 1.3679 + } 1.3680 + 1.3681 + view = view->GetParent(); 1.3682 + } while (view); 1.3683 + // return if the view wasn't found 1.3684 + return; 1.3685 + } 1.3686 + } 1.3687 + } 1.3688 + 1.3689 + NS_RELEASE(gCaptureInfo.mContent); 1.3690 + } 1.3691 + 1.3692 + // disable mouse capture until the next mousedown as a dialog has opened 1.3693 + // or a drag has started. Otherwise, someone could start capture during 1.3694 + // the modal dialog or drag. 1.3695 + gCaptureInfo.mAllowed = false; 1.3696 +} 1.3697 + 1.3698 +void 1.3699 +nsIPresShell::ClearMouseCapture(nsIFrame* aFrame) 1.3700 +{ 1.3701 + if (!gCaptureInfo.mContent) { 1.3702 + gCaptureInfo.mAllowed = false; 1.3703 + return; 1.3704 + } 1.3705 + 1.3706 + // null frame argument means clear the capture 1.3707 + if (!aFrame) { 1.3708 + NS_RELEASE(gCaptureInfo.mContent); 1.3709 + gCaptureInfo.mAllowed = false; 1.3710 + return; 1.3711 + } 1.3712 + 1.3713 + nsIFrame* capturingFrame = gCaptureInfo.mContent->GetPrimaryFrame(); 1.3714 + if (!capturingFrame) { 1.3715 + NS_RELEASE(gCaptureInfo.mContent); 1.3716 + gCaptureInfo.mAllowed = false; 1.3717 + return; 1.3718 + } 1.3719 + 1.3720 + if (nsLayoutUtils::IsAncestorFrameCrossDoc(aFrame, capturingFrame)) { 1.3721 + NS_RELEASE(gCaptureInfo.mContent); 1.3722 + gCaptureInfo.mAllowed = false; 1.3723 + } 1.3724 +} 1.3725 + 1.3726 +nsresult 1.3727 +PresShell::CaptureHistoryState(nsILayoutHistoryState** aState) 1.3728 +{ 1.3729 + NS_PRECONDITION(nullptr != aState, "null state pointer"); 1.3730 + 1.3731 + // We actually have to mess with the docshell here, since we want to 1.3732 + // store the state back in it. 1.3733 + // XXXbz this isn't really right, since this is being called in the 1.3734 + // content viewer's Hide() method... by that point the docshell's 1.3735 + // state could be wrong. We should sort out a better ownership 1.3736 + // model for the layout history state. 1.3737 + nsCOMPtr<nsIDocShell> docShell(mPresContext->GetDocShell()); 1.3738 + if (!docShell) 1.3739 + return NS_ERROR_FAILURE; 1.3740 + 1.3741 + nsCOMPtr<nsILayoutHistoryState> historyState; 1.3742 + docShell->GetLayoutHistoryState(getter_AddRefs(historyState)); 1.3743 + if (!historyState) { 1.3744 + // Create the document state object 1.3745 + historyState = NS_NewLayoutHistoryState(); 1.3746 + docShell->SetLayoutHistoryState(historyState); 1.3747 + } 1.3748 + 1.3749 + *aState = historyState; 1.3750 + NS_IF_ADDREF(*aState); 1.3751 + 1.3752 + // Capture frame state for the entire frame hierarchy 1.3753 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.3754 + if (!rootFrame) return NS_OK; 1.3755 + 1.3756 + mFrameConstructor->CaptureFrameState(rootFrame, historyState); 1.3757 + 1.3758 + return NS_OK; 1.3759 +} 1.3760 + 1.3761 +void 1.3762 +PresShell::UnsuppressAndInvalidate() 1.3763 +{ 1.3764 + // Note: We ignore the EnsureVisible check for resource documents, because 1.3765 + // they won't have a docshell, so they'll always fail EnsureVisible. 1.3766 + if ((!mDocument->IsResourceDoc() && !mPresContext->EnsureVisible()) || 1.3767 + mHaveShutDown) { 1.3768 + // No point; we're about to be torn down anyway. 1.3769 + return; 1.3770 + } 1.3771 + 1.3772 + if (!mDocument->IsResourceDoc()) { 1.3773 + // Notify observers that a new page is about to be drawn. Execute this 1.3774 + // as soon as it is safe to run JS, which is guaranteed to be before we 1.3775 + // go back to the event loop and actually draw the page. 1.3776 + nsContentUtils::AddScriptRunner(new nsBeforeFirstPaintDispatcher(mDocument)); 1.3777 + } 1.3778 + 1.3779 + mPaintingSuppressed = false; 1.3780 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.3781 + if (rootFrame) { 1.3782 + // let's assume that outline on a root frame is not supported 1.3783 + rootFrame->InvalidateFrame(); 1.3784 + 1.3785 + if (mCaretEnabled && mCaret) { 1.3786 + mCaret->CheckCaretDrawingState(); 1.3787 + } 1.3788 + } 1.3789 + 1.3790 + // now that painting is unsuppressed, focus may be set on the document 1.3791 + nsPIDOMWindow *win = mDocument->GetWindow(); 1.3792 + if (win) 1.3793 + win->SetReadyForFocus(); 1.3794 + 1.3795 + if (!mHaveShutDown) { 1.3796 + SynthesizeMouseMove(false); 1.3797 + ScheduleImageVisibilityUpdate(); 1.3798 + } 1.3799 +} 1.3800 + 1.3801 +void 1.3802 +PresShell::UnsuppressPainting() 1.3803 +{ 1.3804 + if (mPaintSuppressionTimer) { 1.3805 + mPaintSuppressionTimer->Cancel(); 1.3806 + mPaintSuppressionTimer = nullptr; 1.3807 + } 1.3808 + 1.3809 + if (mIsDocumentGone || !mPaintingSuppressed) 1.3810 + return; 1.3811 + 1.3812 + // If we have reflows pending, just wait until we process 1.3813 + // the reflows and get all the frames where we want them 1.3814 + // before actually unlocking the painting. Otherwise 1.3815 + // go ahead and unlock now. 1.3816 + if (!mDirtyRoots.IsEmpty()) 1.3817 + mShouldUnsuppressPainting = true; 1.3818 + else 1.3819 + UnsuppressAndInvalidate(); 1.3820 +} 1.3821 + 1.3822 +// Post a request to handle an arbitrary callback after reflow has finished. 1.3823 +nsresult 1.3824 +PresShell::PostReflowCallback(nsIReflowCallback* aCallback) 1.3825 +{ 1.3826 + void* result = AllocateMisc(sizeof(nsCallbackEventRequest)); 1.3827 + nsCallbackEventRequest* request = (nsCallbackEventRequest*)result; 1.3828 + 1.3829 + request->callback = aCallback; 1.3830 + request->next = nullptr; 1.3831 + 1.3832 + if (mLastCallbackEventRequest) { 1.3833 + mLastCallbackEventRequest = mLastCallbackEventRequest->next = request; 1.3834 + } else { 1.3835 + mFirstCallbackEventRequest = request; 1.3836 + mLastCallbackEventRequest = request; 1.3837 + } 1.3838 + 1.3839 + return NS_OK; 1.3840 +} 1.3841 + 1.3842 +void 1.3843 +PresShell::CancelReflowCallback(nsIReflowCallback* aCallback) 1.3844 +{ 1.3845 + nsCallbackEventRequest* before = nullptr; 1.3846 + nsCallbackEventRequest* node = mFirstCallbackEventRequest; 1.3847 + while(node) 1.3848 + { 1.3849 + nsIReflowCallback* callback = node->callback; 1.3850 + 1.3851 + if (callback == aCallback) 1.3852 + { 1.3853 + nsCallbackEventRequest* toFree = node; 1.3854 + if (node == mFirstCallbackEventRequest) { 1.3855 + node = node->next; 1.3856 + mFirstCallbackEventRequest = node; 1.3857 + NS_ASSERTION(before == nullptr, "impossible"); 1.3858 + } else { 1.3859 + node = node->next; 1.3860 + before->next = node; 1.3861 + } 1.3862 + 1.3863 + if (toFree == mLastCallbackEventRequest) { 1.3864 + mLastCallbackEventRequest = before; 1.3865 + } 1.3866 + 1.3867 + FreeMisc(sizeof(nsCallbackEventRequest), toFree); 1.3868 + } else { 1.3869 + before = node; 1.3870 + node = node->next; 1.3871 + } 1.3872 + } 1.3873 +} 1.3874 + 1.3875 +void 1.3876 +PresShell::CancelPostedReflowCallbacks() 1.3877 +{ 1.3878 + while (mFirstCallbackEventRequest) { 1.3879 + nsCallbackEventRequest* node = mFirstCallbackEventRequest; 1.3880 + mFirstCallbackEventRequest = node->next; 1.3881 + if (!mFirstCallbackEventRequest) { 1.3882 + mLastCallbackEventRequest = nullptr; 1.3883 + } 1.3884 + nsIReflowCallback* callback = node->callback; 1.3885 + FreeMisc(sizeof(nsCallbackEventRequest), node); 1.3886 + if (callback) { 1.3887 + callback->ReflowCallbackCanceled(); 1.3888 + } 1.3889 + } 1.3890 +} 1.3891 + 1.3892 +void 1.3893 +PresShell::HandlePostedReflowCallbacks(bool aInterruptible) 1.3894 +{ 1.3895 + bool shouldFlush = false; 1.3896 + 1.3897 + while (mFirstCallbackEventRequest) { 1.3898 + nsCallbackEventRequest* node = mFirstCallbackEventRequest; 1.3899 + mFirstCallbackEventRequest = node->next; 1.3900 + if (!mFirstCallbackEventRequest) { 1.3901 + mLastCallbackEventRequest = nullptr; 1.3902 + } 1.3903 + nsIReflowCallback* callback = node->callback; 1.3904 + FreeMisc(sizeof(nsCallbackEventRequest), node); 1.3905 + if (callback) { 1.3906 + if (callback->ReflowFinished()) { 1.3907 + shouldFlush = true; 1.3908 + } 1.3909 + } 1.3910 + } 1.3911 + 1.3912 + mozFlushType flushType = 1.3913 + aInterruptible ? Flush_InterruptibleLayout : Flush_Layout; 1.3914 + if (shouldFlush && !mIsDestroying) { 1.3915 + FlushPendingNotifications(flushType); 1.3916 + } 1.3917 +} 1.3918 + 1.3919 +bool 1.3920 +PresShell::IsSafeToFlush() const 1.3921 +{ 1.3922 + // Not safe if we are reflowing or in the middle of frame construction 1.3923 + bool isSafeToFlush = !mIsReflowing && 1.3924 + !mChangeNestCount; 1.3925 + 1.3926 + if (isSafeToFlush) { 1.3927 + // Not safe if we are painting 1.3928 + nsViewManager* viewManager = GetViewManager(); 1.3929 + if (viewManager) { 1.3930 + bool isPainting = false; 1.3931 + viewManager->IsPainting(isPainting); 1.3932 + if (isPainting) { 1.3933 + isSafeToFlush = false; 1.3934 + } 1.3935 + } 1.3936 + } 1.3937 + 1.3938 + return isSafeToFlush; 1.3939 +} 1.3940 + 1.3941 + 1.3942 +void 1.3943 +PresShell::FlushPendingNotifications(mozFlushType aType) 1.3944 +{ 1.3945 + // by default, flush animations if aType >= Flush_Style 1.3946 + mozilla::ChangesToFlush flush(aType, aType >= Flush_Style); 1.3947 + FlushPendingNotifications(flush); 1.3948 +} 1.3949 + 1.3950 +void 1.3951 +PresShell::FlushPendingNotifications(mozilla::ChangesToFlush aFlush) 1.3952 +{ 1.3953 + if (mIsZombie) { 1.3954 + return; 1.3955 + } 1.3956 + 1.3957 + /** 1.3958 + * VERY IMPORTANT: If you add some sort of new flushing to this 1.3959 + * method, make sure to add the relevant SetNeedLayoutFlush or 1.3960 + * SetNeedStyleFlush calls on the document. 1.3961 + */ 1.3962 + mozFlushType flushType = aFlush.mFlushType; 1.3963 + 1.3964 +#ifdef MOZ_ENABLE_PROFILER_SPS 1.3965 + static const char flushTypeNames[][20] = { 1.3966 + "Content", 1.3967 + "ContentAndNotify", 1.3968 + "Style", 1.3969 + "InterruptibleLayout", 1.3970 + "Layout", 1.3971 + "Display" 1.3972 + }; 1.3973 + 1.3974 + // Make sure that we don't miss things added to mozFlushType! 1.3975 + MOZ_ASSERT(static_cast<uint32_t>(flushType) <= ArrayLength(flushTypeNames)); 1.3976 + 1.3977 + PROFILER_LABEL_PRINTF("layout", "Flush", "(Flush_%s)", 1.3978 + flushTypeNames[flushType - 1]); 1.3979 +#endif 1.3980 + 1.3981 +#ifdef ACCESSIBILITY 1.3982 +#ifdef DEBUG 1.3983 + nsAccessibilityService* accService = GetAccService(); 1.3984 + if (accService) { 1.3985 + NS_ASSERTION(!accService->IsProcessingRefreshDriverNotification(), 1.3986 + "Flush during accessible tree update!"); 1.3987 + } 1.3988 +#endif 1.3989 +#endif 1.3990 + 1.3991 + NS_ASSERTION(flushType >= Flush_Frames, "Why did we get called?"); 1.3992 + 1.3993 + bool isSafeToFlush = IsSafeToFlush(); 1.3994 + 1.3995 + // If layout could possibly trigger scripts, then it's only safe to flush if 1.3996 + // it's safe to run script. 1.3997 + bool hasHadScriptObject; 1.3998 + if (mDocument->GetScriptHandlingObject(hasHadScriptObject) || 1.3999 + hasHadScriptObject) { 1.4000 + isSafeToFlush = isSafeToFlush && nsContentUtils::IsSafeToRunScript(); 1.4001 + } 1.4002 + 1.4003 + NS_ASSERTION(!isSafeToFlush || mViewManager, "Must have view manager"); 1.4004 + // Make sure the view manager stays alive. 1.4005 + nsRefPtr<nsViewManager> viewManagerDeathGrip = mViewManager; 1.4006 + if (isSafeToFlush && mViewManager) { 1.4007 + // Processing pending notifications can kill us, and some callers only 1.4008 + // hold weak refs when calling FlushPendingNotifications(). :( 1.4009 + nsCOMPtr<nsIPresShell> kungFuDeathGrip(this); 1.4010 + 1.4011 + if (mResizeEvent.IsPending()) { 1.4012 + FireResizeEvent(); 1.4013 + if (mIsDestroying) { 1.4014 + return; 1.4015 + } 1.4016 + } 1.4017 + 1.4018 + // We need to make sure external resource documents are flushed too (for 1.4019 + // example, svg filters that reference a filter in an external document 1.4020 + // need the frames in the external document to be constructed for the 1.4021 + // filter to work). We only need external resources to be flushed when the 1.4022 + // main document is flushing >= Flush_Frames, so we flush external 1.4023 + // resources here instead of nsDocument::FlushPendingNotifications. 1.4024 + mDocument->FlushExternalResources(flushType); 1.4025 + 1.4026 + // Force flushing of any pending content notifications that might have 1.4027 + // queued up while our event was pending. That will ensure that we don't 1.4028 + // construct frames for content right now that's still waiting to be 1.4029 + // notified on, 1.4030 + mDocument->FlushPendingNotifications(Flush_ContentAndNotify); 1.4031 + 1.4032 + // Process pending restyles, since any flush of the presshell wants 1.4033 + // up-to-date style data. 1.4034 + if (!mIsDestroying) { 1.4035 + mViewManager->FlushDelayedResize(false); 1.4036 + mPresContext->FlushPendingMediaFeatureValuesChanged(); 1.4037 + 1.4038 + // Flush any pending update of the user font set, since that could 1.4039 + // cause style changes (for updating ex/ch units, and to cause a 1.4040 + // reflow). 1.4041 + mPresContext->FlushUserFontSet(); 1.4042 + 1.4043 + // Flush any requested SMIL samples. 1.4044 + if (mDocument->HasAnimationController()) { 1.4045 + mDocument->GetAnimationController()->FlushResampleRequests(); 1.4046 + } 1.4047 + 1.4048 + if (aFlush.mFlushAnimations && 1.4049 + nsLayoutUtils::AreAsyncAnimationsEnabled() && 1.4050 + !mPresContext->StyleUpdateForAllAnimationsIsUpToDate()) { 1.4051 + mPresContext->AnimationManager()-> 1.4052 + FlushAnimations(CommonAnimationManager::Cannot_Throttle); 1.4053 + mPresContext->TransitionManager()-> 1.4054 + FlushTransitions(CommonAnimationManager::Cannot_Throttle); 1.4055 + mPresContext->TickLastStyleUpdateForAllAnimations(); 1.4056 + } 1.4057 + 1.4058 + // The FlushResampleRequests() above flushed style changes. 1.4059 + if (!mIsDestroying) { 1.4060 + nsAutoScriptBlocker scriptBlocker; 1.4061 + mPresContext->RestyleManager()->ProcessPendingRestyles(); 1.4062 + } 1.4063 + } 1.4064 + 1.4065 + // Dispatch any 'animationstart' events those (or earlier) restyles 1.4066 + // queued up. 1.4067 + if (!mIsDestroying) { 1.4068 + mPresContext->AnimationManager()->DispatchEvents(); 1.4069 + } 1.4070 + 1.4071 + // Process whatever XBL constructors those restyles queued up. This 1.4072 + // ensures that onload doesn't fire too early and that we won't do extra 1.4073 + // reflows after those constructors run. 1.4074 + if (!mIsDestroying) { 1.4075 + mDocument->BindingManager()->ProcessAttachedQueue(); 1.4076 + } 1.4077 + 1.4078 + // Now those constructors or events might have posted restyle 1.4079 + // events. At the same time, we still need up-to-date style data. 1.4080 + // In particular, reflow depends on style being completely up to 1.4081 + // date. If it's not, then style context reparenting, which can 1.4082 + // happen during reflow, might suddenly pick up the new rules and 1.4083 + // we'll end up with frames whose style doesn't match the frame 1.4084 + // type. 1.4085 + if (!mIsDestroying) { 1.4086 + nsAutoScriptBlocker scriptBlocker; 1.4087 + mPresContext->RestyleManager()->ProcessPendingRestyles(); 1.4088 + } 1.4089 + 1.4090 + 1.4091 + // There might be more pending constructors now, but we're not going to 1.4092 + // worry about them. They can't be triggered during reflow, so we should 1.4093 + // be good. 1.4094 + 1.4095 + if (flushType >= (mSuppressInterruptibleReflows ? Flush_Layout : Flush_InterruptibleLayout) && 1.4096 + !mIsDestroying) { 1.4097 + mFrameConstructor->RecalcQuotesAndCounters(); 1.4098 + mViewManager->FlushDelayedResize(true); 1.4099 + if (ProcessReflowCommands(flushType < Flush_Layout) && mContentToScrollTo) { 1.4100 + // We didn't get interrupted. Go ahead and scroll to our content 1.4101 + DoScrollContentIntoView(); 1.4102 + if (mContentToScrollTo) { 1.4103 + mContentToScrollTo->DeleteProperty(nsGkAtoms::scrolling); 1.4104 + mContentToScrollTo = nullptr; 1.4105 + } 1.4106 + } 1.4107 + } else if (!mIsDestroying && mSuppressInterruptibleReflows && 1.4108 + flushType == Flush_InterruptibleLayout) { 1.4109 + // We suppressed this flush, but the document thinks it doesn't 1.4110 + // need to flush anymore. Let it know what's really going on. 1.4111 + mDocument->SetNeedLayoutFlush(); 1.4112 + } 1.4113 + 1.4114 + if (flushType >= Flush_Layout) { 1.4115 + if (!mIsDestroying) { 1.4116 + mViewManager->UpdateWidgetGeometry(); 1.4117 + } 1.4118 + } 1.4119 + } 1.4120 +} 1.4121 + 1.4122 +void 1.4123 +PresShell::CharacterDataWillChange(nsIDocument *aDocument, 1.4124 + nsIContent* aContent, 1.4125 + CharacterDataChangeInfo* aInfo) 1.4126 +{ 1.4127 + NS_PRECONDITION(!mIsDocumentGone, "Unexpected CharacterDataChanged"); 1.4128 + NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); 1.4129 + 1.4130 + if (mCaret) { 1.4131 + // Invalidate the caret's current location before we call into the frame 1.4132 + // constructor. It is important to do this now, and not wait until the 1.4133 + // resulting reflow, because this call causes continuation frames of the 1.4134 + // text frame the caret is in to forget what part of the content they 1.4135 + // refer to, making it hard for them to return the correct continuation 1.4136 + // frame to the caret. 1.4137 + // 1.4138 + // It's also important to do this before the content actually changes, since 1.4139 + // in bidi text the caret needs to look at the content to determine its 1.4140 + // position and shape. 1.4141 + mCaret->InvalidateOutsideCaret(); 1.4142 + } 1.4143 +} 1.4144 + 1.4145 +void 1.4146 +PresShell::CharacterDataChanged(nsIDocument *aDocument, 1.4147 + nsIContent* aContent, 1.4148 + CharacterDataChangeInfo* aInfo) 1.4149 +{ 1.4150 + NS_PRECONDITION(!mIsDocumentGone, "Unexpected CharacterDataChanged"); 1.4151 + NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); 1.4152 + 1.4153 + nsAutoCauseReflowNotifier crNotifier(this); 1.4154 + 1.4155 + // Call this here so it only happens for real content mutations and 1.4156 + // not cases when the frame constructor calls its own methods to force 1.4157 + // frame reconstruction. 1.4158 + nsIContent *container = aContent->GetParent(); 1.4159 + uint32_t selectorFlags = 1.4160 + container ? (container->GetFlags() & NODE_ALL_SELECTOR_FLAGS) : 0; 1.4161 + if (selectorFlags != 0 && !aContent->IsRootOfAnonymousSubtree()) { 1.4162 + Element* element = container->AsElement(); 1.4163 + if (aInfo->mAppend && !aContent->GetNextSibling()) 1.4164 + mPresContext->RestyleManager()->RestyleForAppend(element, aContent); 1.4165 + else 1.4166 + mPresContext->RestyleManager()->RestyleForInsertOrChange(element, aContent); 1.4167 + } 1.4168 + 1.4169 + mFrameConstructor->CharacterDataChanged(aContent, aInfo); 1.4170 + VERIFY_STYLE_TREE; 1.4171 +} 1.4172 + 1.4173 +void 1.4174 +PresShell::ContentStateChanged(nsIDocument* aDocument, 1.4175 + nsIContent* aContent, 1.4176 + EventStates aStateMask) 1.4177 +{ 1.4178 + NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentStateChanged"); 1.4179 + NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); 1.4180 + 1.4181 + if (mDidInitialize) { 1.4182 + nsAutoCauseReflowNotifier crNotifier(this); 1.4183 + mPresContext->RestyleManager()->ContentStateChanged(aContent, aStateMask); 1.4184 + VERIFY_STYLE_TREE; 1.4185 + } 1.4186 +} 1.4187 + 1.4188 +void 1.4189 +PresShell::DocumentStatesChanged(nsIDocument* aDocument, 1.4190 + EventStates aStateMask) 1.4191 +{ 1.4192 + NS_PRECONDITION(!mIsDocumentGone, "Unexpected DocumentStatesChanged"); 1.4193 + NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); 1.4194 + 1.4195 + if (mDidInitialize && 1.4196 + mStyleSet->HasDocumentStateDependentStyle(mPresContext, 1.4197 + mDocument->GetRootElement(), 1.4198 + aStateMask)) { 1.4199 + mPresContext->RestyleManager()->PostRestyleEvent(mDocument->GetRootElement(), 1.4200 + eRestyle_Subtree, 1.4201 + NS_STYLE_HINT_NONE); 1.4202 + VERIFY_STYLE_TREE; 1.4203 + } 1.4204 + 1.4205 + if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) { 1.4206 + nsIFrame* root = mFrameConstructor->GetRootFrame(); 1.4207 + if (root) { 1.4208 + root->SchedulePaint(); 1.4209 + } 1.4210 + } 1.4211 +} 1.4212 + 1.4213 +void 1.4214 +PresShell::AttributeWillChange(nsIDocument* aDocument, 1.4215 + Element* aElement, 1.4216 + int32_t aNameSpaceID, 1.4217 + nsIAtom* aAttribute, 1.4218 + int32_t aModType) 1.4219 +{ 1.4220 + NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeWillChange"); 1.4221 + NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); 1.4222 + 1.4223 + // XXXwaterson it might be more elegant to wait until after the 1.4224 + // initial reflow to begin observing the document. That would 1.4225 + // squelch any other inappropriate notifications as well. 1.4226 + if (mDidInitialize) { 1.4227 + nsAutoCauseReflowNotifier crNotifier(this); 1.4228 + mPresContext->RestyleManager()->AttributeWillChange(aElement, aNameSpaceID, 1.4229 + aAttribute, aModType); 1.4230 + VERIFY_STYLE_TREE; 1.4231 + } 1.4232 +} 1.4233 + 1.4234 +void 1.4235 +PresShell::AttributeChanged(nsIDocument* aDocument, 1.4236 + Element* aElement, 1.4237 + int32_t aNameSpaceID, 1.4238 + nsIAtom* aAttribute, 1.4239 + int32_t aModType) 1.4240 +{ 1.4241 + NS_PRECONDITION(!mIsDocumentGone, "Unexpected AttributeChanged"); 1.4242 + NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); 1.4243 + 1.4244 + // XXXwaterson it might be more elegant to wait until after the 1.4245 + // initial reflow to begin observing the document. That would 1.4246 + // squelch any other inappropriate notifications as well. 1.4247 + if (mDidInitialize) { 1.4248 + nsAutoCauseReflowNotifier crNotifier(this); 1.4249 + mPresContext->RestyleManager()->AttributeChanged(aElement, aNameSpaceID, 1.4250 + aAttribute, aModType); 1.4251 + VERIFY_STYLE_TREE; 1.4252 + } 1.4253 +} 1.4254 + 1.4255 +void 1.4256 +PresShell::ContentAppended(nsIDocument *aDocument, 1.4257 + nsIContent* aContainer, 1.4258 + nsIContent* aFirstNewContent, 1.4259 + int32_t aNewIndexInContainer) 1.4260 +{ 1.4261 + NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentAppended"); 1.4262 + NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); 1.4263 + NS_PRECONDITION(aContainer, "must have container"); 1.4264 + 1.4265 + if (!mDidInitialize) { 1.4266 + return; 1.4267 + } 1.4268 + 1.4269 + nsAutoCauseReflowNotifier crNotifier(this); 1.4270 + 1.4271 + // Call this here so it only happens for real content mutations and 1.4272 + // not cases when the frame constructor calls its own methods to force 1.4273 + // frame reconstruction. 1.4274 + if (aContainer->IsElement()) { 1.4275 + // Ensure the container is an element before trying to restyle 1.4276 + // because it can be the case that the container is a ShadowRoot 1.4277 + // which is a document fragment. 1.4278 + mPresContext->RestyleManager()-> 1.4279 + RestyleForAppend(aContainer->AsElement(), aFirstNewContent); 1.4280 + } 1.4281 + 1.4282 + mFrameConstructor->ContentAppended(aContainer, aFirstNewContent, true); 1.4283 + 1.4284 + if (static_cast<nsINode*>(aContainer) == static_cast<nsINode*>(aDocument) && 1.4285 + aFirstNewContent->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) { 1.4286 + NotifyFontSizeInflationEnabledIsDirty(); 1.4287 + } 1.4288 + 1.4289 + VERIFY_STYLE_TREE; 1.4290 +} 1.4291 + 1.4292 +void 1.4293 +PresShell::ContentInserted(nsIDocument* aDocument, 1.4294 + nsIContent* aContainer, 1.4295 + nsIContent* aChild, 1.4296 + int32_t aIndexInContainer) 1.4297 +{ 1.4298 + NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentInserted"); 1.4299 + NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); 1.4300 + 1.4301 + if (!mDidInitialize) { 1.4302 + return; 1.4303 + } 1.4304 + 1.4305 + nsAutoCauseReflowNotifier crNotifier(this); 1.4306 + 1.4307 + // Call this here so it only happens for real content mutations and 1.4308 + // not cases when the frame constructor calls its own methods to force 1.4309 + // frame reconstruction. 1.4310 + if (aContainer && aContainer->IsElement()) { 1.4311 + // Ensure the container is an element before trying to restyle 1.4312 + // because it can be the case that the container is a ShadowRoot 1.4313 + // which is a document fragment. 1.4314 + mPresContext->RestyleManager()-> 1.4315 + RestyleForInsertOrChange(aContainer->AsElement(), aChild); 1.4316 + } 1.4317 + 1.4318 + mFrameConstructor->ContentInserted(aContainer, aChild, nullptr, true); 1.4319 + 1.4320 + if (((!aContainer && aDocument) || 1.4321 + (static_cast<nsINode*>(aContainer) == static_cast<nsINode*>(aDocument))) && 1.4322 + aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) { 1.4323 + NotifyFontSizeInflationEnabledIsDirty(); 1.4324 + } 1.4325 + 1.4326 + VERIFY_STYLE_TREE; 1.4327 +} 1.4328 + 1.4329 +void 1.4330 +PresShell::ContentRemoved(nsIDocument *aDocument, 1.4331 + nsIContent* aContainer, 1.4332 + nsIContent* aChild, 1.4333 + int32_t aIndexInContainer, 1.4334 + nsIContent* aPreviousSibling) 1.4335 +{ 1.4336 + NS_PRECONDITION(!mIsDocumentGone, "Unexpected ContentRemoved"); 1.4337 + NS_PRECONDITION(aDocument == mDocument, "Unexpected aDocument"); 1.4338 + 1.4339 + // Make sure that the caret doesn't leave a turd where the child used to be. 1.4340 + if (mCaret) { 1.4341 + mCaret->InvalidateOutsideCaret(); 1.4342 + } 1.4343 + 1.4344 + // Notify the ESM that the content has been removed, so that 1.4345 + // it can clean up any state related to the content. 1.4346 + 1.4347 + // XXX_jwir3: There is no null check for aDocument necessary, since, even 1.4348 + // though by nsIMutationObserver, aDocument could be null, the 1.4349 + // precondition check that mDocument == aDocument ensures that 1.4350 + // aDocument will not be null (since mDocument can't be null unless 1.4351 + // we're still intializing). 1.4352 + mPresContext->EventStateManager()->ContentRemoved(aDocument, aChild); 1.4353 + 1.4354 + nsAutoCauseReflowNotifier crNotifier(this); 1.4355 + 1.4356 + // Call this here so it only happens for real content mutations and 1.4357 + // not cases when the frame constructor calls its own methods to force 1.4358 + // frame reconstruction. 1.4359 + nsIContent* oldNextSibling; 1.4360 + if (aContainer) { 1.4361 + oldNextSibling = aContainer->GetChildAt(aIndexInContainer); 1.4362 + } else { 1.4363 + oldNextSibling = nullptr; 1.4364 + } 1.4365 + 1.4366 + if (aContainer && aContainer->IsElement()) { 1.4367 + mPresContext->RestyleManager()-> 1.4368 + RestyleForRemove(aContainer->AsElement(), aChild, oldNextSibling); 1.4369 + } 1.4370 + 1.4371 + bool didReconstruct; 1.4372 + mFrameConstructor->ContentRemoved(aContainer, aChild, oldNextSibling, 1.4373 + nsCSSFrameConstructor::REMOVE_CONTENT, 1.4374 + &didReconstruct); 1.4375 + 1.4376 + 1.4377 + if (((aContainer && 1.4378 + static_cast<nsINode*>(aContainer) == static_cast<nsINode*>(aDocument)) || 1.4379 + aDocument) && aChild->NodeType() == nsIDOMNode::DOCUMENT_TYPE_NODE) { 1.4380 + NotifyFontSizeInflationEnabledIsDirty(); 1.4381 + } 1.4382 + 1.4383 + VERIFY_STYLE_TREE; 1.4384 +} 1.4385 + 1.4386 +nsresult 1.4387 +PresShell::ReconstructFrames(void) 1.4388 +{ 1.4389 + NS_PRECONDITION(!mFrameConstructor->GetRootFrame() || mDidInitialize, 1.4390 + "Must not have root frame before initial reflow"); 1.4391 + if (!mDidInitialize) { 1.4392 + // Nothing to do here 1.4393 + return NS_OK; 1.4394 + } 1.4395 + 1.4396 + nsCOMPtr<nsIPresShell> kungFuDeathGrip(this); 1.4397 + 1.4398 + // Have to make sure that the content notifications are flushed before we 1.4399 + // start messing with the frame model; otherwise we can get content doubling. 1.4400 + mDocument->FlushPendingNotifications(Flush_ContentAndNotify); 1.4401 + 1.4402 + nsAutoCauseReflowNotifier crNotifier(this); 1.4403 + mFrameConstructor->BeginUpdate(); 1.4404 + nsresult rv = mFrameConstructor->ReconstructDocElementHierarchy(); 1.4405 + VERIFY_STYLE_TREE; 1.4406 + mFrameConstructor->EndUpdate(); 1.4407 + 1.4408 + return rv; 1.4409 +} 1.4410 + 1.4411 +void 1.4412 +nsIPresShell::ReconstructStyleDataInternal() 1.4413 +{ 1.4414 + nsAutoTArray<nsRefPtr<mozilla::dom::Element>,1> scopeRoots; 1.4415 + mChangedScopeStyleRoots.SwapElements(scopeRoots); 1.4416 + 1.4417 + if (mStylesHaveChanged) { 1.4418 + // If we need to restyle everything, no need to restyle individual 1.4419 + // scoped style roots. 1.4420 + scopeRoots.Clear(); 1.4421 + } 1.4422 + 1.4423 + mStylesHaveChanged = false; 1.4424 + 1.4425 + if (mIsDestroying) { 1.4426 + // We don't want to mess with restyles at this point 1.4427 + return; 1.4428 + } 1.4429 + 1.4430 + if (mPresContext) { 1.4431 + mPresContext->RebuildUserFontSet(); 1.4432 + } 1.4433 + 1.4434 + Element* root = mDocument->GetRootElement(); 1.4435 + if (!mDidInitialize) { 1.4436 + // Nothing to do here, since we have no frames yet 1.4437 + return; 1.4438 + } 1.4439 + 1.4440 + if (!root) { 1.4441 + // No content to restyle 1.4442 + return; 1.4443 + } 1.4444 + 1.4445 + RestyleManager* restyleManager = mPresContext->RestyleManager(); 1.4446 + if (scopeRoots.IsEmpty()) { 1.4447 + // If scopeRoots is empty, we know that mStylesHaveChanged was true at 1.4448 + // the beginning of this function, and that we need to restyle the whole 1.4449 + // document. 1.4450 + restyleManager->PostRestyleEvent(root, eRestyle_Subtree, 1.4451 + NS_STYLE_HINT_NONE); 1.4452 + } else { 1.4453 + for (uint32_t i = 0; i < scopeRoots.Length(); i++) { 1.4454 + Element* scopeRoot = scopeRoots[i]; 1.4455 + restyleManager->PostRestyleEvent(scopeRoot, eRestyle_Subtree, 1.4456 + NS_STYLE_HINT_NONE); 1.4457 + } 1.4458 + } 1.4459 +} 1.4460 + 1.4461 +void 1.4462 +nsIPresShell::ReconstructStyleDataExternal() 1.4463 +{ 1.4464 + ReconstructStyleDataInternal(); 1.4465 +} 1.4466 + 1.4467 +void 1.4468 +PresShell::RecordStyleSheetChange(nsIStyleSheet* aStyleSheet) 1.4469 +{ 1.4470 + if (mStylesHaveChanged) 1.4471 + return; 1.4472 + 1.4473 + nsRefPtr<nsCSSStyleSheet> cssStyleSheet = do_QueryObject(aStyleSheet); 1.4474 + if (cssStyleSheet) { 1.4475 + Element* scopeElement = cssStyleSheet->GetScopeElement(); 1.4476 + if (scopeElement) { 1.4477 + mChangedScopeStyleRoots.AppendElement(scopeElement); 1.4478 + return; 1.4479 + } 1.4480 + } 1.4481 + 1.4482 + mStylesHaveChanged = true; 1.4483 +} 1.4484 + 1.4485 +void 1.4486 +PresShell::StyleSheetAdded(nsIDocument *aDocument, 1.4487 + nsIStyleSheet* aStyleSheet, 1.4488 + bool aDocumentSheet) 1.4489 +{ 1.4490 + // We only care when enabled sheets are added 1.4491 + NS_PRECONDITION(aStyleSheet, "Must have a style sheet!"); 1.4492 + 1.4493 + if (aStyleSheet->IsApplicable() && aStyleSheet->HasRules()) { 1.4494 + RecordStyleSheetChange(aStyleSheet); 1.4495 + } 1.4496 +} 1.4497 + 1.4498 +void 1.4499 +PresShell::StyleSheetRemoved(nsIDocument *aDocument, 1.4500 + nsIStyleSheet* aStyleSheet, 1.4501 + bool aDocumentSheet) 1.4502 +{ 1.4503 + // We only care when enabled sheets are removed 1.4504 + NS_PRECONDITION(aStyleSheet, "Must have a style sheet!"); 1.4505 + 1.4506 + if (aStyleSheet->IsApplicable() && aStyleSheet->HasRules()) { 1.4507 + RecordStyleSheetChange(aStyleSheet); 1.4508 + } 1.4509 +} 1.4510 + 1.4511 +void 1.4512 +PresShell::StyleSheetApplicableStateChanged(nsIDocument *aDocument, 1.4513 + nsIStyleSheet* aStyleSheet, 1.4514 + bool aApplicable) 1.4515 +{ 1.4516 + if (aStyleSheet->HasRules()) { 1.4517 + RecordStyleSheetChange(aStyleSheet); 1.4518 + } 1.4519 +} 1.4520 + 1.4521 +void 1.4522 +PresShell::StyleRuleChanged(nsIDocument *aDocument, 1.4523 + nsIStyleSheet* aStyleSheet, 1.4524 + nsIStyleRule* aOldStyleRule, 1.4525 + nsIStyleRule* aNewStyleRule) 1.4526 +{ 1.4527 + RecordStyleSheetChange(aStyleSheet); 1.4528 +} 1.4529 + 1.4530 +void 1.4531 +PresShell::StyleRuleAdded(nsIDocument *aDocument, 1.4532 + nsIStyleSheet* aStyleSheet, 1.4533 + nsIStyleRule* aStyleRule) 1.4534 +{ 1.4535 + RecordStyleSheetChange(aStyleSheet); 1.4536 +} 1.4537 + 1.4538 +void 1.4539 +PresShell::StyleRuleRemoved(nsIDocument *aDocument, 1.4540 + nsIStyleSheet* aStyleSheet, 1.4541 + nsIStyleRule* aStyleRule) 1.4542 +{ 1.4543 + RecordStyleSheetChange(aStyleSheet); 1.4544 +} 1.4545 + 1.4546 +nsIFrame* 1.4547 +PresShell::GetRealPrimaryFrameFor(nsIContent* aContent) const 1.4548 +{ 1.4549 + if (aContent->GetDocument() != GetDocument()) { 1.4550 + return nullptr; 1.4551 + } 1.4552 + nsIFrame *primaryFrame = aContent->GetPrimaryFrame(); 1.4553 + if (!primaryFrame) 1.4554 + return nullptr; 1.4555 + return nsPlaceholderFrame::GetRealFrameFor(primaryFrame); 1.4556 +} 1.4557 + 1.4558 +nsIFrame* 1.4559 +PresShell::GetPlaceholderFrameFor(nsIFrame* aFrame) const 1.4560 +{ 1.4561 + return mFrameConstructor->GetPlaceholderFrameFor(aFrame); 1.4562 +} 1.4563 + 1.4564 +nsresult 1.4565 +PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags, 1.4566 + nscolor aBackgroundColor, 1.4567 + gfxContext* aThebesContext) 1.4568 +{ 1.4569 + NS_ENSURE_TRUE(!(aFlags & RENDER_IS_UNTRUSTED), NS_ERROR_NOT_IMPLEMENTED); 1.4570 + 1.4571 + nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext(); 1.4572 + if (rootPresContext) { 1.4573 + rootPresContext->FlushWillPaintObservers(); 1.4574 + if (mIsDestroying) 1.4575 + return NS_OK; 1.4576 + } 1.4577 + 1.4578 + nsAutoScriptBlocker blockScripts; 1.4579 + 1.4580 + // Set up the rectangle as the path in aThebesContext 1.4581 + gfxRect r(0, 0, 1.4582 + nsPresContext::AppUnitsToFloatCSSPixels(aRect.width), 1.4583 + nsPresContext::AppUnitsToFloatCSSPixels(aRect.height)); 1.4584 + aThebesContext->NewPath(); 1.4585 +#ifdef MOZ_GFX_OPTIMIZE_MOBILE 1.4586 + aThebesContext->Rectangle(r, true); 1.4587 +#else 1.4588 + aThebesContext->Rectangle(r); 1.4589 +#endif 1.4590 + 1.4591 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.4592 + if (!rootFrame) { 1.4593 + // Nothing to paint, just fill the rect 1.4594 + aThebesContext->SetColor(gfxRGBA(aBackgroundColor)); 1.4595 + aThebesContext->Fill(); 1.4596 + return NS_OK; 1.4597 + } 1.4598 + 1.4599 + gfxContextAutoSaveRestore save(aThebesContext); 1.4600 + 1.4601 + gfxContext::GraphicsOperator oldOperator = aThebesContext->CurrentOperator(); 1.4602 + if (oldOperator == gfxContext::OPERATOR_OVER) { 1.4603 + // Clip to the destination rectangle before we push the group, 1.4604 + // to limit the size of the temporary surface 1.4605 + aThebesContext->Clip(); 1.4606 + } 1.4607 + 1.4608 + // we want the window to be composited as a single image using 1.4609 + // whatever operator was set; set OPERATOR_OVER here, which is 1.4610 + // either already the case, or overrides the operator in a group. 1.4611 + // the original operator will be present when we PopGroup. 1.4612 + // we can avoid using a temporary surface if we're using OPERATOR_OVER 1.4613 + bool needsGroup = oldOperator != gfxContext::OPERATOR_OVER; 1.4614 + 1.4615 + if (needsGroup) { 1.4616 + aThebesContext->PushGroup(NS_GET_A(aBackgroundColor) == 0xff ? 1.4617 + gfxContentType::COLOR : 1.4618 + gfxContentType::COLOR_ALPHA); 1.4619 + aThebesContext->Save(); 1.4620 + 1.4621 + if (oldOperator != gfxContext::OPERATOR_OVER) { 1.4622 + // Clip now while we paint to the temporary surface. For 1.4623 + // non-source-bounded operators (e.g., SOURCE), we need to do clip 1.4624 + // here after we've pushed the group, so that eventually popping 1.4625 + // the group and painting it will be able to clear the entire 1.4626 + // destination surface. 1.4627 + aThebesContext->Clip(); 1.4628 + aThebesContext->SetOperator(gfxContext::OPERATOR_OVER); 1.4629 + } 1.4630 + } 1.4631 + 1.4632 + aThebesContext->Translate(gfxPoint(-nsPresContext::AppUnitsToFloatCSSPixels(aRect.x), 1.4633 + -nsPresContext::AppUnitsToFloatCSSPixels(aRect.y))); 1.4634 + 1.4635 + nsDeviceContext* devCtx = mPresContext->DeviceContext(); 1.4636 + gfxFloat scale = gfxFloat(devCtx->AppUnitsPerDevPixel())/nsPresContext::AppUnitsPerCSSPixel(); 1.4637 + aThebesContext->Scale(scale, scale); 1.4638 + 1.4639 + // Since canvas APIs use floats to set up their matrices, we may have 1.4640 + // some slight inaccuracy here. Adjust matrix components that are 1.4641 + // integers up to the accuracy of floats to be those integers. 1.4642 + aThebesContext->NudgeCurrentMatrixToIntegers(); 1.4643 + 1.4644 + AutoSaveRestoreRenderingState _(this); 1.4645 + 1.4646 + nsRefPtr<nsRenderingContext> rc = new nsRenderingContext(); 1.4647 + rc->Init(devCtx, aThebesContext); 1.4648 + 1.4649 + bool wouldFlushRetainedLayers = false; 1.4650 + uint32_t flags = nsLayoutUtils::PAINT_IGNORE_SUPPRESSION; 1.4651 + if (aThebesContext->CurrentMatrix().HasNonIntegerTranslation()) { 1.4652 + flags |= nsLayoutUtils::PAINT_IN_TRANSFORM; 1.4653 + } 1.4654 + if (!(aFlags & RENDER_ASYNC_DECODE_IMAGES)) { 1.4655 + flags |= nsLayoutUtils::PAINT_SYNC_DECODE_IMAGES; 1.4656 + } 1.4657 + if (aFlags & RENDER_USE_WIDGET_LAYERS) { 1.4658 + // We only support using widget layers on display root's with widgets. 1.4659 + nsView* view = rootFrame->GetView(); 1.4660 + if (view && view->GetWidget() && 1.4661 + nsLayoutUtils::GetDisplayRootFrame(rootFrame) == rootFrame) { 1.4662 + flags |= nsLayoutUtils::PAINT_WIDGET_LAYERS; 1.4663 + } 1.4664 + } 1.4665 + if (!(aFlags & RENDER_CARET)) { 1.4666 + wouldFlushRetainedLayers = true; 1.4667 + flags |= nsLayoutUtils::PAINT_HIDE_CARET; 1.4668 + } 1.4669 + if (aFlags & RENDER_IGNORE_VIEWPORT_SCROLLING) { 1.4670 + wouldFlushRetainedLayers = !IgnoringViewportScrolling(); 1.4671 + mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_IGNORING_VIEWPORT_SCROLLING); 1.4672 + } 1.4673 + if (aFlags & RENDER_DRAWWINDOW_NOT_FLUSHING) { 1.4674 + mRenderFlags = ChangeFlag(mRenderFlags, true, STATE_DRAWWINDOW_NOT_FLUSHING); 1.4675 + } 1.4676 + if (aFlags & RENDER_DOCUMENT_RELATIVE) { 1.4677 + // XXX be smarter about this ... drawWindow might want a rect 1.4678 + // that's "pretty close" to what our retained layer tree covers. 1.4679 + // In that case, it wouldn't disturb normal rendering too much, 1.4680 + // and we should allow it. 1.4681 + wouldFlushRetainedLayers = true; 1.4682 + flags |= nsLayoutUtils::PAINT_DOCUMENT_RELATIVE; 1.4683 + } 1.4684 + 1.4685 + // Don't let drawWindow blow away our retained layer tree 1.4686 + if ((flags & nsLayoutUtils::PAINT_WIDGET_LAYERS) && wouldFlushRetainedLayers) { 1.4687 + flags &= ~nsLayoutUtils::PAINT_WIDGET_LAYERS; 1.4688 + } 1.4689 + 1.4690 + nsLayoutUtils::PaintFrame(rc, rootFrame, nsRegion(aRect), 1.4691 + aBackgroundColor, flags); 1.4692 + 1.4693 + // if we had to use a group, paint it to the destination now 1.4694 + if (needsGroup) { 1.4695 + aThebesContext->Restore(); 1.4696 + aThebesContext->PopGroupToSource(); 1.4697 + aThebesContext->Paint(); 1.4698 + } 1.4699 + 1.4700 + return NS_OK; 1.4701 +} 1.4702 + 1.4703 +/* 1.4704 + * Clip the display list aList to a range. Returns the clipped 1.4705 + * rectangle surrounding the range. 1.4706 + */ 1.4707 +nsRect 1.4708 +PresShell::ClipListToRange(nsDisplayListBuilder *aBuilder, 1.4709 + nsDisplayList* aList, 1.4710 + nsRange* aRange) 1.4711 +{ 1.4712 + // iterate though the display items and add up the bounding boxes of each. 1.4713 + // This will allow the total area of the frames within the range to be 1.4714 + // determined. To do this, remove an item from the bottom of the list, check 1.4715 + // whether it should be part of the range, and if so, append it to the top 1.4716 + // of the temporary list tmpList. If the item is a text frame at the end of 1.4717 + // the selection range, clip it to the portion of the text frame that is 1.4718 + // part of the selection. Then, append the wrapper to the top of the list. 1.4719 + // Otherwise, just delete the item and don't append it. 1.4720 + nsRect surfaceRect; 1.4721 + nsDisplayList tmpList; 1.4722 + 1.4723 + nsDisplayItem* i; 1.4724 + while ((i = aList->RemoveBottom())) { 1.4725 + // itemToInsert indiciates the item that should be inserted into the 1.4726 + // temporary list. If null, no item should be inserted. 1.4727 + nsDisplayItem* itemToInsert = nullptr; 1.4728 + nsIFrame* frame = i->Frame(); 1.4729 + nsIContent* content = frame->GetContent(); 1.4730 + if (content) { 1.4731 + bool atStart = (content == aRange->GetStartParent()); 1.4732 + bool atEnd = (content == aRange->GetEndParent()); 1.4733 + if ((atStart || atEnd) && frame->GetType() == nsGkAtoms::textFrame) { 1.4734 + int32_t frameStartOffset, frameEndOffset; 1.4735 + frame->GetOffsets(frameStartOffset, frameEndOffset); 1.4736 + 1.4737 + int32_t hilightStart = 1.4738 + atStart ? std::max(aRange->StartOffset(), frameStartOffset) : frameStartOffset; 1.4739 + int32_t hilightEnd = 1.4740 + atEnd ? std::min(aRange->EndOffset(), frameEndOffset) : frameEndOffset; 1.4741 + if (hilightStart < hilightEnd) { 1.4742 + // determine the location of the start and end edges of the range. 1.4743 + nsPoint startPoint, endPoint; 1.4744 + frame->GetPointFromOffset(hilightStart, &startPoint); 1.4745 + frame->GetPointFromOffset(hilightEnd, &endPoint); 1.4746 + 1.4747 + // the clip rectangle is determined by taking the the start and 1.4748 + // end points of the range, offset from the reference frame. 1.4749 + // Because of rtl, the end point may be to the left of the 1.4750 + // start point, so x is set to the lowest value 1.4751 + nsRect textRect(aBuilder->ToReferenceFrame(frame), frame->GetSize()); 1.4752 + nscoord x = std::min(startPoint.x, endPoint.x); 1.4753 + textRect.x += x; 1.4754 + textRect.width = std::max(startPoint.x, endPoint.x) - x; 1.4755 + surfaceRect.UnionRect(surfaceRect, textRect); 1.4756 + 1.4757 + DisplayItemClip newClip; 1.4758 + newClip.SetTo(textRect); 1.4759 + newClip.IntersectWith(i->GetClip()); 1.4760 + i->SetClip(aBuilder, newClip); 1.4761 + itemToInsert = i; 1.4762 + } 1.4763 + } 1.4764 + // Don't try to descend into subdocuments. 1.4765 + // If this ever changes we'd need to add handling for subdocuments with 1.4766 + // different zoom levels. 1.4767 + else if (content->GetCurrentDoc() == 1.4768 + aRange->GetStartParent()->GetCurrentDoc()) { 1.4769 + // if the node is within the range, append it to the temporary list 1.4770 + bool before, after; 1.4771 + nsresult rv = 1.4772 + nsRange::CompareNodeToRange(content, aRange, &before, &after); 1.4773 + if (NS_SUCCEEDED(rv) && !before && !after) { 1.4774 + itemToInsert = i; 1.4775 + bool snap; 1.4776 + surfaceRect.UnionRect(surfaceRect, i->GetBounds(aBuilder, &snap)); 1.4777 + } 1.4778 + } 1.4779 + } 1.4780 + 1.4781 + // insert the item into the list if necessary. If the item has a child 1.4782 + // list, insert that as well 1.4783 + nsDisplayList* sublist = i->GetSameCoordinateSystemChildren(); 1.4784 + if (itemToInsert || sublist) { 1.4785 + tmpList.AppendToTop(itemToInsert ? itemToInsert : i); 1.4786 + // if the item is a list, iterate over it as well 1.4787 + if (sublist) 1.4788 + surfaceRect.UnionRect(surfaceRect, 1.4789 + ClipListToRange(aBuilder, sublist, aRange)); 1.4790 + } 1.4791 + else { 1.4792 + // otherwise, just delete the item and don't readd it to the list 1.4793 + i->~nsDisplayItem(); 1.4794 + } 1.4795 + } 1.4796 + 1.4797 + // now add all the items back onto the original list again 1.4798 + aList->AppendToTop(&tmpList); 1.4799 + 1.4800 + return surfaceRect; 1.4801 +} 1.4802 + 1.4803 +#ifdef DEBUG 1.4804 +#include <stdio.h> 1.4805 + 1.4806 +static bool gDumpRangePaintList = false; 1.4807 +#endif 1.4808 + 1.4809 +RangePaintInfo* 1.4810 +PresShell::CreateRangePaintInfo(nsIDOMRange* aRange, 1.4811 + nsRect& aSurfaceRect, 1.4812 + bool aForPrimarySelection) 1.4813 +{ 1.4814 + RangePaintInfo* info = nullptr; 1.4815 + 1.4816 + nsRange* range = static_cast<nsRange*>(aRange); 1.4817 + 1.4818 + nsIFrame* ancestorFrame; 1.4819 + nsIFrame* rootFrame = GetRootFrame(); 1.4820 + 1.4821 + // If the start or end of the range is the document, just use the root 1.4822 + // frame, otherwise get the common ancestor of the two endpoints of the 1.4823 + // range. 1.4824 + nsINode* startParent = range->GetStartParent(); 1.4825 + nsINode* endParent = range->GetEndParent(); 1.4826 + nsIDocument* doc = startParent->GetCurrentDoc(); 1.4827 + if (startParent == doc || endParent == doc) { 1.4828 + ancestorFrame = rootFrame; 1.4829 + } 1.4830 + else { 1.4831 + nsINode* ancestor = nsContentUtils::GetCommonAncestor(startParent, endParent); 1.4832 + NS_ASSERTION(!ancestor || ancestor->IsNodeOfType(nsINode::eCONTENT), 1.4833 + "common ancestor is not content"); 1.4834 + if (!ancestor || !ancestor->IsNodeOfType(nsINode::eCONTENT)) 1.4835 + return nullptr; 1.4836 + 1.4837 + nsIContent* ancestorContent = static_cast<nsIContent*>(ancestor); 1.4838 + ancestorFrame = ancestorContent->GetPrimaryFrame(); 1.4839 + 1.4840 + // use the nearest ancestor frame that includes all continuations as the 1.4841 + // root for building the display list 1.4842 + while (ancestorFrame && 1.4843 + nsLayoutUtils::GetNextContinuationOrIBSplitSibling(ancestorFrame)) 1.4844 + ancestorFrame = ancestorFrame->GetParent(); 1.4845 + } 1.4846 + 1.4847 + if (!ancestorFrame) 1.4848 + return nullptr; 1.4849 + 1.4850 + info = new RangePaintInfo(range, ancestorFrame); 1.4851 + 1.4852 + nsRect ancestorRect = ancestorFrame->GetVisualOverflowRect(); 1.4853 + 1.4854 + // get a display list containing the range 1.4855 + info->mBuilder.SetIncludeAllOutOfFlows(); 1.4856 + if (aForPrimarySelection) { 1.4857 + info->mBuilder.SetSelectedFramesOnly(); 1.4858 + } 1.4859 + info->mBuilder.EnterPresShell(ancestorFrame, ancestorRect); 1.4860 + ancestorFrame->BuildDisplayListForStackingContext(&info->mBuilder, 1.4861 + ancestorRect, &info->mList); 1.4862 + 1.4863 +#ifdef DEBUG 1.4864 + if (gDumpRangePaintList) { 1.4865 + fprintf(stderr, "CreateRangePaintInfo --- before ClipListToRange:\n"); 1.4866 + nsFrame::PrintDisplayList(&(info->mBuilder), info->mList); 1.4867 + } 1.4868 +#endif 1.4869 + 1.4870 + nsRect rangeRect = ClipListToRange(&info->mBuilder, &info->mList, range); 1.4871 + 1.4872 + info->mBuilder.LeavePresShell(ancestorFrame, ancestorRect); 1.4873 + 1.4874 +#ifdef DEBUG 1.4875 + if (gDumpRangePaintList) { 1.4876 + fprintf(stderr, "CreateRangePaintInfo --- after ClipListToRange:\n"); 1.4877 + nsFrame::PrintDisplayList(&(info->mBuilder), info->mList); 1.4878 + } 1.4879 +#endif 1.4880 + 1.4881 + // determine the offset of the reference frame for the display list 1.4882 + // to the root frame. This will allow the coordinates used when painting 1.4883 + // to all be offset from the same point 1.4884 + info->mRootOffset = ancestorFrame->GetOffsetTo(rootFrame); 1.4885 + rangeRect.MoveBy(info->mRootOffset); 1.4886 + aSurfaceRect.UnionRect(aSurfaceRect, rangeRect); 1.4887 + 1.4888 + return info; 1.4889 +} 1.4890 + 1.4891 +TemporaryRef<SourceSurface> 1.4892 +PresShell::PaintRangePaintInfo(nsTArray<nsAutoPtr<RangePaintInfo> >* aItems, 1.4893 + nsISelection* aSelection, 1.4894 + nsIntRegion* aRegion, 1.4895 + nsRect aArea, 1.4896 + nsIntPoint& aPoint, 1.4897 + nsIntRect* aScreenRect) 1.4898 +{ 1.4899 + nsPresContext* pc = GetPresContext(); 1.4900 + if (!pc || aArea.width == 0 || aArea.height == 0) 1.4901 + return nullptr; 1.4902 + 1.4903 + nsDeviceContext* deviceContext = pc->DeviceContext(); 1.4904 + 1.4905 + // use the rectangle to create the surface 1.4906 + nsIntRect pixelArea = aArea.ToOutsidePixels(pc->AppUnitsPerDevPixel()); 1.4907 + 1.4908 + // if the area of the image is larger than the maximum area, scale it down 1.4909 + float scale = 0.0; 1.4910 + nsIntRect rootScreenRect = 1.4911 + GetRootFrame()->GetScreenRectInAppUnits().ToNearestPixels( 1.4912 + pc->AppUnitsPerDevPixel()); 1.4913 + 1.4914 + // if the image is larger in one or both directions than half the size of 1.4915 + // the available screen area, scale the image down to that size. 1.4916 + nsRect maxSize; 1.4917 + deviceContext->GetClientRect(maxSize); 1.4918 + nscoord maxWidth = pc->AppUnitsToDevPixels(maxSize.width >> 1); 1.4919 + nscoord maxHeight = pc->AppUnitsToDevPixels(maxSize.height >> 1); 1.4920 + bool resize = (pixelArea.width > maxWidth || pixelArea.height > maxHeight); 1.4921 + if (resize) { 1.4922 + scale = 1.0; 1.4923 + // divide the maximum size by the image size in both directions. Whichever 1.4924 + // direction produces the smallest result determines how much should be 1.4925 + // scaled. 1.4926 + if (pixelArea.width > maxWidth) 1.4927 + scale = std::min(scale, float(maxWidth) / pixelArea.width); 1.4928 + if (pixelArea.height > maxHeight) 1.4929 + scale = std::min(scale, float(maxHeight) / pixelArea.height); 1.4930 + 1.4931 + pixelArea.width = NSToIntFloor(float(pixelArea.width) * scale); 1.4932 + pixelArea.height = NSToIntFloor(float(pixelArea.height) * scale); 1.4933 + 1.4934 + // adjust the screen position based on the rescaled size 1.4935 + nscoord left = rootScreenRect.x + pixelArea.x; 1.4936 + nscoord top = rootScreenRect.y + pixelArea.y; 1.4937 + aScreenRect->x = NSToIntFloor(aPoint.x - float(aPoint.x - left) * scale); 1.4938 + aScreenRect->y = NSToIntFloor(aPoint.y - float(aPoint.y - top) * scale); 1.4939 + } 1.4940 + else { 1.4941 + // move aScreenRect to the position of the surface in screen coordinates 1.4942 + aScreenRect->MoveTo(rootScreenRect.x + pixelArea.x, rootScreenRect.y + pixelArea.y); 1.4943 + } 1.4944 + aScreenRect->width = pixelArea.width; 1.4945 + aScreenRect->height = pixelArea.height; 1.4946 + 1.4947 + RefPtr<DrawTarget> dt = 1.4948 + gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( 1.4949 + IntSize(pixelArea.width, pixelArea.height), 1.4950 + SurfaceFormat::B8G8R8A8); 1.4951 + if (!dt) { 1.4952 + return nullptr; 1.4953 + } 1.4954 + 1.4955 + nsRefPtr<gfxContext> ctx = new gfxContext(dt); 1.4956 + nsRefPtr<nsRenderingContext> rc = new nsRenderingContext(); 1.4957 + rc->Init(deviceContext, ctx); 1.4958 + 1.4959 + if (aRegion) { 1.4960 + // Convert aRegion from CSS pixels to dev pixels 1.4961 + nsIntRegion region = 1.4962 + aRegion->ToAppUnits(nsPresContext::AppUnitsPerCSSPixel()) 1.4963 + .ToOutsidePixels(pc->AppUnitsPerDevPixel()); 1.4964 + rc->SetClip(region); 1.4965 + } 1.4966 + 1.4967 + if (resize) 1.4968 + rc->Scale(scale, scale); 1.4969 + 1.4970 + // translate so that points are relative to the surface area 1.4971 + rc->Translate(-aArea.TopLeft()); 1.4972 + 1.4973 + // temporarily hide the selection so that text is drawn normally. If a 1.4974 + // selection is being rendered, use that, otherwise use the presshell's 1.4975 + // selection. 1.4976 + nsRefPtr<nsFrameSelection> frameSelection; 1.4977 + if (aSelection) { 1.4978 + frameSelection = static_cast<Selection*>(aSelection)->GetFrameSelection(); 1.4979 + } 1.4980 + else { 1.4981 + frameSelection = FrameSelection(); 1.4982 + } 1.4983 + int16_t oldDisplaySelection = frameSelection->GetDisplaySelection(); 1.4984 + frameSelection->SetDisplaySelection(nsISelectionController::SELECTION_HIDDEN); 1.4985 + 1.4986 + // next, paint each range in the selection 1.4987 + int32_t count = aItems->Length(); 1.4988 + for (int32_t i = 0; i < count; i++) { 1.4989 + RangePaintInfo* rangeInfo = (*aItems)[i]; 1.4990 + // the display lists paint relative to the offset from the reference 1.4991 + // frame, so translate the rendering context 1.4992 + nsRenderingContext::AutoPushTranslation 1.4993 + translate(rc, rangeInfo->mRootOffset); 1.4994 + 1.4995 + aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y); 1.4996 + nsRegion visible(aArea); 1.4997 + rangeInfo->mList.ComputeVisibilityForRoot(&rangeInfo->mBuilder, &visible); 1.4998 + rangeInfo->mList.PaintRoot(&rangeInfo->mBuilder, rc, nsDisplayList::PAINT_DEFAULT); 1.4999 + aArea.MoveBy(rangeInfo->mRootOffset.x, rangeInfo->mRootOffset.y); 1.5000 + } 1.5001 + 1.5002 + // restore the old selection display state 1.5003 + frameSelection->SetDisplaySelection(oldDisplaySelection); 1.5004 + 1.5005 + return dt->Snapshot(); 1.5006 +} 1.5007 + 1.5008 +TemporaryRef<SourceSurface> 1.5009 +PresShell::RenderNode(nsIDOMNode* aNode, 1.5010 + nsIntRegion* aRegion, 1.5011 + nsIntPoint& aPoint, 1.5012 + nsIntRect* aScreenRect) 1.5013 +{ 1.5014 + // area will hold the size of the surface needed to draw the node, measured 1.5015 + // from the root frame. 1.5016 + nsRect area; 1.5017 + nsTArray<nsAutoPtr<RangePaintInfo> > rangeItems; 1.5018 + 1.5019 + // nothing to draw if the node isn't in a document 1.5020 + nsCOMPtr<nsINode> node = do_QueryInterface(aNode); 1.5021 + if (!node->IsInDoc()) 1.5022 + return nullptr; 1.5023 + 1.5024 + nsRefPtr<nsRange> range = new nsRange(node); 1.5025 + if (NS_FAILED(range->SelectNode(aNode))) 1.5026 + return nullptr; 1.5027 + 1.5028 + RangePaintInfo* info = CreateRangePaintInfo(range, area, false); 1.5029 + if (info && !rangeItems.AppendElement(info)) { 1.5030 + delete info; 1.5031 + return nullptr; 1.5032 + } 1.5033 + 1.5034 + if (aRegion) { 1.5035 + // combine the area with the supplied region 1.5036 + nsIntRect rrectPixels = aRegion->GetBounds(); 1.5037 + 1.5038 + nsRect rrect = rrectPixels.ToAppUnits(nsPresContext::AppUnitsPerCSSPixel()); 1.5039 + area.IntersectRect(area, rrect); 1.5040 + 1.5041 + nsPresContext* pc = GetPresContext(); 1.5042 + if (!pc) 1.5043 + return nullptr; 1.5044 + 1.5045 + // move the region so that it is offset from the topleft corner of the surface 1.5046 + aRegion->MoveBy(-pc->AppUnitsToDevPixels(area.x), 1.5047 + -pc->AppUnitsToDevPixels(area.y)); 1.5048 + } 1.5049 + 1.5050 + return PaintRangePaintInfo(&rangeItems, nullptr, aRegion, area, aPoint, 1.5051 + aScreenRect); 1.5052 +} 1.5053 + 1.5054 +TemporaryRef<SourceSurface> 1.5055 +PresShell::RenderSelection(nsISelection* aSelection, 1.5056 + nsIntPoint& aPoint, 1.5057 + nsIntRect* aScreenRect) 1.5058 +{ 1.5059 + // area will hold the size of the surface needed to draw the selection, 1.5060 + // measured from the root frame. 1.5061 + nsRect area; 1.5062 + nsTArray<nsAutoPtr<RangePaintInfo> > rangeItems; 1.5063 + 1.5064 + // iterate over each range and collect them into the rangeItems array. 1.5065 + // This is done so that the size of selection can be determined so as 1.5066 + // to allocate a surface area 1.5067 + int32_t numRanges; 1.5068 + aSelection->GetRangeCount(&numRanges); 1.5069 + NS_ASSERTION(numRanges > 0, "RenderSelection called with no selection"); 1.5070 + 1.5071 + for (int32_t r = 0; r < numRanges; r++) 1.5072 + { 1.5073 + nsCOMPtr<nsIDOMRange> range; 1.5074 + aSelection->GetRangeAt(r, getter_AddRefs(range)); 1.5075 + 1.5076 + RangePaintInfo* info = CreateRangePaintInfo(range, area, true); 1.5077 + if (info && !rangeItems.AppendElement(info)) { 1.5078 + delete info; 1.5079 + return nullptr; 1.5080 + } 1.5081 + } 1.5082 + 1.5083 + return PaintRangePaintInfo(&rangeItems, aSelection, nullptr, area, aPoint, 1.5084 + aScreenRect); 1.5085 +} 1.5086 + 1.5087 +void 1.5088 +PresShell::AddPrintPreviewBackgroundItem(nsDisplayListBuilder& aBuilder, 1.5089 + nsDisplayList& aList, 1.5090 + nsIFrame* aFrame, 1.5091 + const nsRect& aBounds) 1.5092 +{ 1.5093 + aList.AppendNewToBottom(new (&aBuilder) 1.5094 + nsDisplaySolidColor(&aBuilder, aFrame, aBounds, NS_RGB(115, 115, 115))); 1.5095 +} 1.5096 + 1.5097 +static bool 1.5098 +AddCanvasBackgroundColor(const nsDisplayList& aList, nsIFrame* aCanvasFrame, 1.5099 + nscolor aColor) 1.5100 +{ 1.5101 + for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) { 1.5102 + if (i->Frame() == aCanvasFrame && 1.5103 + i->GetType() == nsDisplayItem::TYPE_CANVAS_BACKGROUND_COLOR) { 1.5104 + nsDisplayCanvasBackgroundColor* bg = static_cast<nsDisplayCanvasBackgroundColor*>(i); 1.5105 + bg->SetExtraBackgroundColor(aColor); 1.5106 + return true; 1.5107 + } 1.5108 + nsDisplayList* sublist = i->GetSameCoordinateSystemChildren(); 1.5109 + if (sublist && AddCanvasBackgroundColor(*sublist, aCanvasFrame, aColor)) 1.5110 + return true; 1.5111 + } 1.5112 + return false; 1.5113 +} 1.5114 + 1.5115 +void 1.5116 +PresShell::AddCanvasBackgroundColorItem(nsDisplayListBuilder& aBuilder, 1.5117 + nsDisplayList& aList, 1.5118 + nsIFrame* aFrame, 1.5119 + const nsRect& aBounds, 1.5120 + nscolor aBackstopColor, 1.5121 + uint32_t aFlags) 1.5122 +{ 1.5123 + if (aBounds.IsEmpty()) { 1.5124 + return; 1.5125 + } 1.5126 + // We don't want to add an item for the canvas background color if the frame 1.5127 + // (sub)tree we are painting doesn't include any canvas frames. There isn't 1.5128 + // an easy way to check this directly, but if we check if the root of the 1.5129 + // (sub)tree we are painting is a canvas frame that should cover us in all 1.5130 + // cases (it will usually be a viewport frame when we have a canvas frame in 1.5131 + // the (sub)tree). 1.5132 + if (!(aFlags & nsIPresShell::FORCE_DRAW) && 1.5133 + !nsCSSRendering::IsCanvasFrame(aFrame)) { 1.5134 + return; 1.5135 + } 1.5136 + 1.5137 + nscolor bgcolor = NS_ComposeColors(aBackstopColor, mCanvasBackgroundColor); 1.5138 + if (NS_GET_A(bgcolor) == 0) 1.5139 + return; 1.5140 + 1.5141 + // To make layers work better, we want to avoid having a big non-scrolled 1.5142 + // color background behind a scrolled transparent background. Instead, 1.5143 + // we'll try to move the color background into the scrolled content 1.5144 + // by making nsDisplayCanvasBackground paint it. 1.5145 + if (!aFrame->GetParent()) { 1.5146 + nsIScrollableFrame* sf = 1.5147 + aFrame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable(); 1.5148 + if (sf) { 1.5149 + nsCanvasFrame* canvasFrame = do_QueryFrame(sf->GetScrolledFrame()); 1.5150 + if (canvasFrame && canvasFrame->IsVisibleForPainting(&aBuilder)) { 1.5151 + if (AddCanvasBackgroundColor(aList, canvasFrame, bgcolor)) 1.5152 + return; 1.5153 + } 1.5154 + } 1.5155 + } 1.5156 + 1.5157 + aList.AppendNewToBottom( 1.5158 + new (&aBuilder) nsDisplaySolidColor(&aBuilder, aFrame, aBounds, bgcolor)); 1.5159 +} 1.5160 + 1.5161 +static bool IsTransparentContainerElement(nsPresContext* aPresContext) 1.5162 +{ 1.5163 + nsCOMPtr<nsIDocShellTreeItem> docShellItem = aPresContext->GetDocShell(); 1.5164 + nsCOMPtr<nsPIDOMWindow> pwin(do_GetInterface(docShellItem)); 1.5165 + if (!pwin) 1.5166 + return false; 1.5167 + nsCOMPtr<nsIContent> containerElement = 1.5168 + do_QueryInterface(pwin->GetFrameElementInternal()); 1.5169 + return containerElement && 1.5170 + containerElement->HasAttr(kNameSpaceID_None, nsGkAtoms::transparent); 1.5171 +} 1.5172 + 1.5173 +nscolor PresShell::GetDefaultBackgroundColorToDraw() 1.5174 +{ 1.5175 + if (!mPresContext || !mPresContext->GetBackgroundColorDraw()) { 1.5176 + return NS_RGB(255,255,255); 1.5177 + } 1.5178 + return mPresContext->DefaultBackgroundColor(); 1.5179 +} 1.5180 + 1.5181 +void PresShell::UpdateCanvasBackground() 1.5182 +{ 1.5183 + // If we have a frame tree and it has style information that 1.5184 + // specifies the background color of the canvas, update our local 1.5185 + // cache of that color. 1.5186 + nsIFrame* rootStyleFrame = FrameConstructor()->GetRootElementStyleFrame(); 1.5187 + if (rootStyleFrame) { 1.5188 + nsStyleContext* bgStyle = 1.5189 + nsCSSRendering::FindRootFrameBackground(rootStyleFrame); 1.5190 + // XXX We should really be passing the canvasframe, not the root element 1.5191 + // style frame but we don't have access to the canvasframe here. It isn't 1.5192 + // a problem because only a few frames can return something other than true 1.5193 + // and none of them would be a canvas frame or root element style frame. 1.5194 + bool drawBackgroundImage; 1.5195 + bool drawBackgroundColor; 1.5196 + 1.5197 + mCanvasBackgroundColor = 1.5198 + nsCSSRendering::DetermineBackgroundColor(mPresContext, bgStyle, 1.5199 + rootStyleFrame, 1.5200 + drawBackgroundImage, 1.5201 + drawBackgroundColor); 1.5202 + if (GetPresContext()->IsCrossProcessRootContentDocument() && 1.5203 + !IsTransparentContainerElement(mPresContext)) { 1.5204 + mCanvasBackgroundColor = 1.5205 + NS_ComposeColors(GetDefaultBackgroundColorToDraw(), mCanvasBackgroundColor); 1.5206 + } 1.5207 + } 1.5208 + 1.5209 + // If the root element of the document (ie html) has style 'display: none' 1.5210 + // then the document's background color does not get drawn; cache the 1.5211 + // color we actually draw. 1.5212 + if (!FrameConstructor()->GetRootElementFrame()) { 1.5213 + mCanvasBackgroundColor = GetDefaultBackgroundColorToDraw(); 1.5214 + } 1.5215 + if (XRE_GetProcessType() == GeckoProcessType_Content) { 1.5216 + if (TabChild* tabChild = TabChild::GetFrom(this)) { 1.5217 + tabChild->SetBackgroundColor(mCanvasBackgroundColor); 1.5218 + } 1.5219 + } 1.5220 +} 1.5221 + 1.5222 +nscolor PresShell::ComputeBackstopColor(nsView* aDisplayRoot) 1.5223 +{ 1.5224 + nsIWidget* widget = aDisplayRoot->GetWidget(); 1.5225 + if (widget && (widget->GetTransparencyMode() != eTransparencyOpaque || 1.5226 + widget->WidgetPaintsBackground())) { 1.5227 + // Within a transparent widget, so the backstop color must be 1.5228 + // totally transparent. 1.5229 + return NS_RGBA(0,0,0,0); 1.5230 + } 1.5231 + // Within an opaque widget (or no widget at all), so the backstop 1.5232 + // color must be totally opaque. The user's default background 1.5233 + // as reported by the prescontext is guaranteed to be opaque. 1.5234 + return GetDefaultBackgroundColorToDraw(); 1.5235 +} 1.5236 + 1.5237 +struct PaintParams { 1.5238 + nscolor mBackgroundColor; 1.5239 +}; 1.5240 + 1.5241 +LayerManager* PresShell::GetLayerManager() 1.5242 +{ 1.5243 + NS_ASSERTION(mViewManager, "Should have view manager"); 1.5244 + 1.5245 + nsView* rootView = mViewManager->GetRootView(); 1.5246 + if (rootView) { 1.5247 + if (nsIWidget* widget = rootView->GetWidget()) { 1.5248 + return widget->GetLayerManager(); 1.5249 + } 1.5250 + } 1.5251 + return nullptr; 1.5252 +} 1.5253 + 1.5254 +void PresShell::SetIgnoreViewportScrolling(bool aIgnore) 1.5255 +{ 1.5256 + if (IgnoringViewportScrolling() == aIgnore) { 1.5257 + return; 1.5258 + } 1.5259 + RenderingState state(this); 1.5260 + state.mRenderFlags = ChangeFlag(state.mRenderFlags, aIgnore, 1.5261 + STATE_IGNORING_VIEWPORT_SCROLLING); 1.5262 + SetRenderingState(state); 1.5263 +} 1.5264 + 1.5265 +nsresult PresShell::SetResolution(float aXResolution, float aYResolution) 1.5266 +{ 1.5267 + if (!(aXResolution > 0.0 && aYResolution > 0.0)) { 1.5268 + return NS_ERROR_ILLEGAL_VALUE; 1.5269 + } 1.5270 + if (aXResolution == mXResolution && aYResolution == mYResolution) { 1.5271 + return NS_OK; 1.5272 + } 1.5273 + RenderingState state(this); 1.5274 + state.mXResolution = aXResolution; 1.5275 + state.mYResolution = aYResolution; 1.5276 + SetRenderingState(state); 1.5277 + return NS_OK; 1.5278 +} 1.5279 + 1.5280 +gfxSize PresShell::GetCumulativeResolution() 1.5281 +{ 1.5282 + gfxSize resolution = GetResolution(); 1.5283 + nsPresContext* parentCtx = GetPresContext()->GetParentPresContext(); 1.5284 + if (parentCtx) { 1.5285 + resolution = resolution * parentCtx->PresShell()->GetCumulativeResolution(); 1.5286 + } 1.5287 + return resolution; 1.5288 +} 1.5289 + 1.5290 +void PresShell::SetRenderingState(const RenderingState& aState) 1.5291 +{ 1.5292 + if (mRenderFlags != aState.mRenderFlags) { 1.5293 + // Rendering state changed in a way that forces us to flush any 1.5294 + // retained layers we might already have. 1.5295 + LayerManager* manager = GetLayerManager(); 1.5296 + if (manager) { 1.5297 + FrameLayerBuilder::InvalidateAllLayers(manager); 1.5298 + } 1.5299 + } 1.5300 + 1.5301 + mRenderFlags = aState.mRenderFlags; 1.5302 + mXResolution = aState.mXResolution; 1.5303 + mYResolution = aState.mYResolution; 1.5304 +} 1.5305 + 1.5306 +void PresShell::SynthesizeMouseMove(bool aFromScroll) 1.5307 +{ 1.5308 + if (!sSynthMouseMove) 1.5309 + return; 1.5310 + 1.5311 + if (mPaintingSuppressed || !mIsActive || !mPresContext) { 1.5312 + return; 1.5313 + } 1.5314 + 1.5315 + if (!mPresContext->IsRoot()) { 1.5316 + nsIPresShell* rootPresShell = GetRootPresShell(); 1.5317 + if (rootPresShell) { 1.5318 + rootPresShell->SynthesizeMouseMove(aFromScroll); 1.5319 + } 1.5320 + return; 1.5321 + } 1.5322 + 1.5323 + if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) 1.5324 + return; 1.5325 + 1.5326 + if (!mSynthMouseMoveEvent.IsPending()) { 1.5327 + nsRefPtr<nsSynthMouseMoveEvent> ev = 1.5328 + new nsSynthMouseMoveEvent(this, aFromScroll); 1.5329 + 1.5330 + if (!GetPresContext()->RefreshDriver()->AddRefreshObserver(ev, 1.5331 + Flush_Display)) { 1.5332 + NS_WARNING("failed to dispatch nsSynthMouseMoveEvent"); 1.5333 + return; 1.5334 + } 1.5335 + 1.5336 + mSynthMouseMoveEvent = ev; 1.5337 + } 1.5338 +} 1.5339 + 1.5340 +/** 1.5341 + * Find the first floating view with a widget in a postorder traversal of the 1.5342 + * view tree that contains the point. Thus more deeply nested floating views 1.5343 + * are preferred over their ancestors, and floating views earlier in the 1.5344 + * view hierarchy (i.e., added later) are preferred over their siblings. 1.5345 + * This is adequate for finding the "topmost" floating view under a point, 1.5346 + * given that floating views don't supporting having a specific z-index. 1.5347 + * 1.5348 + * We cannot exit early when aPt is outside the view bounds, because floating 1.5349 + * views aren't necessarily included in their parent's bounds, so this could 1.5350 + * traverse the entire view hierarchy --- use carefully. 1.5351 + */ 1.5352 +static nsView* FindFloatingViewContaining(nsView* aView, nsPoint aPt) 1.5353 +{ 1.5354 + if (aView->GetVisibility() == nsViewVisibility_kHide) 1.5355 + // No need to look into descendants. 1.5356 + return nullptr; 1.5357 + 1.5358 + nsIFrame* frame = aView->GetFrame(); 1.5359 + if (frame) { 1.5360 + if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) || 1.5361 + !frame->PresContext()->PresShell()->IsActive()) { 1.5362 + return nullptr; 1.5363 + } 1.5364 + } 1.5365 + 1.5366 + for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) { 1.5367 + nsView* r = FindFloatingViewContaining(v, v->ConvertFromParentCoords(aPt)); 1.5368 + if (r) 1.5369 + return r; 1.5370 + } 1.5371 + 1.5372 + if (aView->GetFloating() && aView->HasWidget() && 1.5373 + aView->GetDimensions().Contains(aPt)) 1.5374 + return aView; 1.5375 + 1.5376 + return nullptr; 1.5377 +} 1.5378 + 1.5379 +/* 1.5380 + * This finds the first view containing the given point in a postorder 1.5381 + * traversal of the view tree that contains the point, assuming that the 1.5382 + * point is not in a floating view. It assumes that only floating views 1.5383 + * extend outside the bounds of their parents. 1.5384 + * 1.5385 + * This methods should only be called if FindFloatingViewContaining 1.5386 + * returns null. 1.5387 + */ 1.5388 +static nsView* FindViewContaining(nsView* aView, nsPoint aPt) 1.5389 +{ 1.5390 + if (!aView->GetDimensions().Contains(aPt) || 1.5391 + aView->GetVisibility() == nsViewVisibility_kHide) { 1.5392 + return nullptr; 1.5393 + } 1.5394 + 1.5395 + nsIFrame* frame = aView->GetFrame(); 1.5396 + if (frame) { 1.5397 + if (!frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) || 1.5398 + !frame->PresContext()->PresShell()->IsActive()) { 1.5399 + return nullptr; 1.5400 + } 1.5401 + } 1.5402 + 1.5403 + for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) { 1.5404 + nsView* r = FindViewContaining(v, v->ConvertFromParentCoords(aPt)); 1.5405 + if (r) 1.5406 + return r; 1.5407 + } 1.5408 + 1.5409 + return aView; 1.5410 +} 1.5411 + 1.5412 +void 1.5413 +PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll) 1.5414 +{ 1.5415 + // If drag session has started, we shouldn't synthesize mousemove event. 1.5416 + nsCOMPtr<nsIDragSession> dragSession = nsContentUtils::GetDragSession(); 1.5417 + if (dragSession) { 1.5418 + mSynthMouseMoveEvent.Forget(); 1.5419 + return; 1.5420 + } 1.5421 + 1.5422 + // allow new event to be posted while handling this one only if the 1.5423 + // source of the event is a scroll (to prevent infinite reflow loops) 1.5424 + if (aFromScroll) { 1.5425 + mSynthMouseMoveEvent.Forget(); 1.5426 + } 1.5427 + 1.5428 + nsView* rootView = mViewManager ? mViewManager->GetRootView() : nullptr; 1.5429 + if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) || 1.5430 + !rootView || !rootView->HasWidget() || !mPresContext) { 1.5431 + mSynthMouseMoveEvent.Forget(); 1.5432 + return; 1.5433 + } 1.5434 + 1.5435 + NS_ASSERTION(mPresContext->IsRoot(), "Only a root pres shell should be here"); 1.5436 + 1.5437 + // Hold a ref to ourselves so DispatchEvent won't destroy us (since 1.5438 + // we need to access members after we call DispatchEvent). 1.5439 + nsCOMPtr<nsIPresShell> kungFuDeathGrip(this); 1.5440 + 1.5441 +#ifdef DEBUG_MOUSE_LOCATION 1.5442 + printf("[ps=%p]synthesizing mouse move to (%d,%d)\n", 1.5443 + this, mMouseLocation.x, mMouseLocation.y); 1.5444 +#endif 1.5445 + 1.5446 + int32_t APD = mPresContext->AppUnitsPerDevPixel(); 1.5447 + 1.5448 + // We need a widget to put in the event we are going to dispatch so we look 1.5449 + // for a view that has a widget and the mouse location is over. We first look 1.5450 + // for floating views, if there isn't one we use the root view. |view| holds 1.5451 + // that view. 1.5452 + nsView* view = nullptr; 1.5453 + 1.5454 + // The appunits per devpixel ratio of |view|. 1.5455 + int32_t viewAPD; 1.5456 + 1.5457 + // refPoint will be mMouseLocation relative to the widget of |view|, the 1.5458 + // widget we will put in the event we dispatch, in viewAPD appunits 1.5459 + nsPoint refpoint(0, 0); 1.5460 + 1.5461 + // We always dispatch the event to the pres shell that contains the view that 1.5462 + // the mouse is over. pointVM is the VM of that pres shell. 1.5463 + nsViewManager *pointVM = nullptr; 1.5464 + 1.5465 + // This could be a bit slow (traverses entire view hierarchy) 1.5466 + // but it's OK to do it once per synthetic mouse event 1.5467 + view = FindFloatingViewContaining(rootView, mMouseLocation); 1.5468 + if (!view) { 1.5469 + view = rootView; 1.5470 + nsView *pointView = FindViewContaining(rootView, mMouseLocation); 1.5471 + // pointView can be null in situations related to mouse capture 1.5472 + pointVM = (pointView ? pointView : view)->GetViewManager(); 1.5473 + refpoint = mMouseLocation + rootView->ViewToWidgetOffset(); 1.5474 + viewAPD = APD; 1.5475 + } else { 1.5476 + pointVM = view->GetViewManager(); 1.5477 + nsIFrame* frame = view->GetFrame(); 1.5478 + NS_ASSERTION(frame, "floating views can't be anonymous"); 1.5479 + viewAPD = frame->PresContext()->AppUnitsPerDevPixel(); 1.5480 + refpoint = mMouseLocation.ConvertAppUnits(APD, viewAPD); 1.5481 + refpoint -= view->GetOffsetTo(rootView); 1.5482 + refpoint += view->ViewToWidgetOffset(); 1.5483 + } 1.5484 + NS_ASSERTION(view->GetWidget(), "view should have a widget here"); 1.5485 + WidgetMouseEvent event(true, NS_MOUSE_MOVE, view->GetWidget(), 1.5486 + WidgetMouseEvent::eSynthesized); 1.5487 + event.refPoint = LayoutDeviceIntPoint::FromAppUnitsToNearest(refpoint, viewAPD); 1.5488 + event.time = PR_IntervalNow(); 1.5489 + // XXX set event.modifiers ? 1.5490 + // XXX mnakano I think that we should get the latest information from widget. 1.5491 + 1.5492 + nsCOMPtr<nsIPresShell> shell = pointVM->GetPresShell(); 1.5493 + if (shell) { 1.5494 + shell->DispatchSynthMouseMove(&event, !aFromScroll); 1.5495 + } 1.5496 + 1.5497 + if (!aFromScroll) { 1.5498 + mSynthMouseMoveEvent.Forget(); 1.5499 + } 1.5500 +} 1.5501 + 1.5502 +/* static */ void 1.5503 +PresShell::MarkImagesInListVisible(const nsDisplayList& aList) 1.5504 +{ 1.5505 + for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) { 1.5506 + nsDisplayList* sublist = item->GetChildren(); 1.5507 + if (sublist) { 1.5508 + MarkImagesInListVisible(*sublist); 1.5509 + continue; 1.5510 + } 1.5511 + nsIFrame* f = item->Frame(); 1.5512 + // We could check the type of the display item, only a handful can hold an 1.5513 + // image loading content. 1.5514 + // dont bother nscomptr here, it is wasteful 1.5515 + nsCOMPtr<nsIImageLoadingContent> content(do_QueryInterface(f->GetContent())); 1.5516 + if (content) { 1.5517 + // use the presshell containing the image 1.5518 + PresShell* presShell = static_cast<PresShell*>(f->PresContext()->PresShell()); 1.5519 + uint32_t count = presShell->mVisibleImages.Count(); 1.5520 + presShell->mVisibleImages.PutEntry(content); 1.5521 + if (presShell->mVisibleImages.Count() > count) { 1.5522 + // content was added to mVisibleImages, so we need to increment its visible count 1.5523 + content->IncrementVisibleCount(); 1.5524 + } 1.5525 + } 1.5526 + } 1.5527 +} 1.5528 + 1.5529 +static PLDHashOperator 1.5530 +RemoveAndStore(nsRefPtrHashKey<nsIImageLoadingContent>* aEntry, void* userArg) 1.5531 +{ 1.5532 + nsTArray< nsRefPtr<nsIImageLoadingContent> >* array = 1.5533 + static_cast< nsTArray< nsRefPtr<nsIImageLoadingContent> >* >(userArg); 1.5534 + array->AppendElement(aEntry->GetKey()); 1.5535 + return PL_DHASH_REMOVE; 1.5536 +} 1.5537 + 1.5538 +void 1.5539 +PresShell::RebuildImageVisibility(const nsDisplayList& aList) 1.5540 +{ 1.5541 + MOZ_ASSERT(!mImageVisibilityVisited, "already visited?"); 1.5542 + mImageVisibilityVisited = true; 1.5543 + // Remove the entries of the mVisibleImages hashtable and put them in the 1.5544 + // beforeImageList array. 1.5545 + nsTArray< nsRefPtr<nsIImageLoadingContent> > beforeImageList; 1.5546 + beforeImageList.SetCapacity(mVisibleImages.Count()); 1.5547 + mVisibleImages.EnumerateEntries(RemoveAndStore, &beforeImageList); 1.5548 + MarkImagesInListVisible(aList); 1.5549 + for (uint32_t i = 0; i < beforeImageList.Length(); ++i) { 1.5550 + beforeImageList[i]->DecrementVisibleCount(); 1.5551 + } 1.5552 +} 1.5553 + 1.5554 +/* static */ void 1.5555 +PresShell::ClearImageVisibilityVisited(nsView* aView, bool aClear) 1.5556 +{ 1.5557 + nsViewManager* vm = aView->GetViewManager(); 1.5558 + if (aClear) { 1.5559 + PresShell* presShell = static_cast<PresShell*>(vm->GetPresShell()); 1.5560 + if (!presShell->mImageVisibilityVisited) { 1.5561 + presShell->ClearVisibleImagesList(); 1.5562 + } 1.5563 + presShell->mImageVisibilityVisited = false; 1.5564 + } 1.5565 + for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) { 1.5566 + ClearImageVisibilityVisited(v, v->GetViewManager() != vm); 1.5567 + } 1.5568 +} 1.5569 + 1.5570 +static PLDHashOperator 1.5571 +DecrementVisibleCount(nsRefPtrHashKey<nsIImageLoadingContent>* aEntry, void* userArg) 1.5572 +{ 1.5573 + aEntry->GetKey()->DecrementVisibleCount(); 1.5574 + return PL_DHASH_NEXT; 1.5575 +} 1.5576 + 1.5577 +void 1.5578 +PresShell::ClearVisibleImagesList() 1.5579 +{ 1.5580 + mVisibleImages.EnumerateEntries(DecrementVisibleCount, nullptr); 1.5581 + mVisibleImages.Clear(); 1.5582 +} 1.5583 + 1.5584 +void 1.5585 +PresShell::UpdateImageVisibility() 1.5586 +{ 1.5587 + MOZ_ASSERT(!mPresContext || mPresContext->IsRootContentDocument(), 1.5588 + "updating image visibility on a non-root content document?"); 1.5589 + 1.5590 + mUpdateImageVisibilityEvent.Revoke(); 1.5591 + 1.5592 + if (mHaveShutDown || mIsDestroying) { 1.5593 + return; 1.5594 + } 1.5595 + 1.5596 + // call update on that frame 1.5597 + nsIFrame* rootFrame = GetRootFrame(); 1.5598 + if (!rootFrame) { 1.5599 + ClearVisibleImagesList(); 1.5600 + return; 1.5601 + } 1.5602 + 1.5603 + // We could walk the frame tree directly and skip creating a display list for 1.5604 + // better perf. 1.5605 + nsRect updateRect(nsPoint(0, 0), rootFrame->GetSize()); 1.5606 + nsDisplayListBuilder builder(rootFrame, nsDisplayListBuilder::IMAGE_VISIBILITY, true); 1.5607 + builder.IgnorePaintSuppression(); 1.5608 + builder.EnterPresShell(rootFrame, updateRect); 1.5609 + nsDisplayList list; 1.5610 + rootFrame->BuildDisplayListForStackingContext(&builder, updateRect, &list); 1.5611 + builder.LeavePresShell(rootFrame, updateRect); 1.5612 + 1.5613 + RebuildImageVisibility(list); 1.5614 + 1.5615 + ClearImageVisibilityVisited(rootFrame->GetView(), true); 1.5616 + 1.5617 + list.DeleteAll(); 1.5618 +} 1.5619 + 1.5620 +bool 1.5621 +PresShell::AssumeAllImagesVisible() 1.5622 +{ 1.5623 + static bool sImageVisibilityEnabled = true; 1.5624 + static bool sImageVisibilityEnabledForBrowserElementsOnly = false; 1.5625 + static bool sImageVisibilityPrefCached = false; 1.5626 + 1.5627 + if (!sImageVisibilityPrefCached) { 1.5628 + Preferences::AddBoolVarCache(&sImageVisibilityEnabled, 1.5629 + "layout.imagevisibility.enabled", true); 1.5630 + Preferences::AddBoolVarCache(&sImageVisibilityEnabledForBrowserElementsOnly, 1.5631 + "layout.imagevisibility.enabled_for_browser_elements_only", false); 1.5632 + sImageVisibilityPrefCached = true; 1.5633 + } 1.5634 + 1.5635 + if ((!sImageVisibilityEnabled && 1.5636 + !sImageVisibilityEnabledForBrowserElementsOnly) || 1.5637 + !mPresContext || !mDocument) { 1.5638 + return true; 1.5639 + } 1.5640 + 1.5641 + // We assume all images are visible in print, print preview, chrome, xul, and 1.5642 + // resource docs and don't keep track of them. 1.5643 + if (mPresContext->Type() == nsPresContext::eContext_PrintPreview || 1.5644 + mPresContext->Type() == nsPresContext::eContext_Print || 1.5645 + mPresContext->IsChrome() || 1.5646 + mDocument->IsResourceDoc() || 1.5647 + mDocument->IsXUL()) { 1.5648 + return true; 1.5649 + } 1.5650 + 1.5651 + if (!sImageVisibilityEnabled && 1.5652 + sImageVisibilityEnabledForBrowserElementsOnly) { 1.5653 + nsCOMPtr<nsIDocShell> docshell(mPresContext->GetDocShell()); 1.5654 + if (!docshell || !docshell->GetIsInBrowserElement()) { 1.5655 + return true; 1.5656 + } 1.5657 + } 1.5658 + 1.5659 + return false; 1.5660 +} 1.5661 + 1.5662 +void 1.5663 +PresShell::ScheduleImageVisibilityUpdate() 1.5664 +{ 1.5665 + if (AssumeAllImagesVisible()) 1.5666 + return; 1.5667 + 1.5668 + if (!mPresContext->IsRootContentDocument()) { 1.5669 + nsPresContext* presContext = mPresContext->GetToplevelContentDocumentPresContext(); 1.5670 + if (!presContext) 1.5671 + return; 1.5672 + MOZ_ASSERT(presContext->IsRootContentDocument(), 1.5673 + "Didn't get a root prescontext from GetToplevelContentDocumentPresContext?"); 1.5674 + presContext->PresShell()->ScheduleImageVisibilityUpdate(); 1.5675 + return; 1.5676 + } 1.5677 + 1.5678 + if (mHaveShutDown || mIsDestroying) 1.5679 + return; 1.5680 + 1.5681 + if (mUpdateImageVisibilityEvent.IsPending()) 1.5682 + return; 1.5683 + 1.5684 + nsRefPtr<nsRunnableMethod<PresShell> > ev = 1.5685 + NS_NewRunnableMethod(this, &PresShell::UpdateImageVisibility); 1.5686 + if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) { 1.5687 + mUpdateImageVisibilityEvent = ev; 1.5688 + } 1.5689 +} 1.5690 + 1.5691 +void 1.5692 +PresShell::EnsureImageInVisibleList(nsIImageLoadingContent* aImage) 1.5693 +{ 1.5694 + if (AssumeAllImagesVisible()) { 1.5695 + aImage->IncrementVisibleCount(); 1.5696 + return; 1.5697 + } 1.5698 + 1.5699 +#ifdef DEBUG 1.5700 + // if it has a frame make sure its in this presshell 1.5701 + nsCOMPtr<nsIContent> content = do_QueryInterface(aImage); 1.5702 + if (content) { 1.5703 + PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell()); 1.5704 + MOZ_ASSERT(!shell || shell == this, "wrong shell"); 1.5705 + } 1.5706 +#endif 1.5707 + 1.5708 + if (!mVisibleImages.Contains(aImage)) { 1.5709 + mVisibleImages.PutEntry(aImage); 1.5710 + aImage->IncrementVisibleCount(); 1.5711 + } 1.5712 +} 1.5713 + 1.5714 +void 1.5715 +PresShell::RemoveImageFromVisibleList(nsIImageLoadingContent* aImage) 1.5716 +{ 1.5717 +#ifdef DEBUG 1.5718 + // if it has a frame make sure its in this presshell 1.5719 + nsCOMPtr<nsIContent> content = do_QueryInterface(aImage); 1.5720 + if (content) { 1.5721 + PresShell* shell = static_cast<PresShell*>(content->OwnerDoc()->GetShell()); 1.5722 + MOZ_ASSERT(!shell || shell == this, "wrong shell"); 1.5723 + } 1.5724 +#endif 1.5725 + 1.5726 + if (AssumeAllImagesVisible()) { 1.5727 + MOZ_ASSERT(mVisibleImages.Count() == 0, "shouldn't have any images in the table"); 1.5728 + return; 1.5729 + } 1.5730 + 1.5731 + uint32_t count = mVisibleImages.Count(); 1.5732 + mVisibleImages.RemoveEntry(aImage); 1.5733 + if (mVisibleImages.Count() < count) { 1.5734 + // aImage was in the hashtable, so we need to decrement its visible count 1.5735 + aImage->DecrementVisibleCount(); 1.5736 + } 1.5737 +} 1.5738 + 1.5739 +class nsAutoNotifyDidPaint 1.5740 +{ 1.5741 +public: 1.5742 + nsAutoNotifyDidPaint(PresShell* aShell, uint32_t aFlags) 1.5743 + : mShell(aShell), mFlags(aFlags) 1.5744 + { 1.5745 + } 1.5746 + ~nsAutoNotifyDidPaint() 1.5747 + { 1.5748 + mShell->GetPresContext()->NotifyDidPaintForSubtree(mFlags); 1.5749 + } 1.5750 + 1.5751 +private: 1.5752 + PresShell* mShell; 1.5753 + uint32_t mFlags; 1.5754 +}; 1.5755 + 1.5756 +class AutoUpdateHitRegion 1.5757 +{ 1.5758 +public: 1.5759 + AutoUpdateHitRegion(PresShell* aShell, nsIFrame* aFrame) 1.5760 + : mShell(aShell), mFrame(aFrame) 1.5761 + { 1.5762 + } 1.5763 + ~AutoUpdateHitRegion() 1.5764 + { 1.5765 + if (XRE_GetProcessType() != GeckoProcessType_Content || 1.5766 + !mFrame || !mShell) { 1.5767 + return; 1.5768 + } 1.5769 + TabChild* tabChild = TabChild::GetFrom(mShell); 1.5770 + if (!tabChild || !tabChild->GetUpdateHitRegion()) { 1.5771 + return; 1.5772 + } 1.5773 + nsRegion region; 1.5774 + nsDisplayListBuilder builder(mFrame, 1.5775 + nsDisplayListBuilder::EVENT_DELIVERY, 1.5776 + /* aBuildCert= */ false); 1.5777 + nsDisplayList list; 1.5778 + nsAutoTArray<nsIFrame*, 100> outFrames; 1.5779 + nsDisplayItem::HitTestState hitTestState; 1.5780 + nsRect bounds = mShell->GetPresContext()->GetVisibleArea(); 1.5781 + builder.EnterPresShell(mFrame, bounds); 1.5782 + mFrame->BuildDisplayListForStackingContext(&builder, bounds, &list); 1.5783 + builder.LeavePresShell(mFrame, bounds); 1.5784 + list.HitTest(&builder, bounds, &hitTestState, &outFrames); 1.5785 + list.DeleteAll(); 1.5786 + for (int32_t i = outFrames.Length() - 1; i >= 0; --i) { 1.5787 + region.Or(region, nsLayoutUtils::TransformFrameRectToAncestor( 1.5788 + outFrames[i], nsRect(nsPoint(0, 0), outFrames[i]->GetSize()), mFrame)); 1.5789 + } 1.5790 + tabChild->UpdateHitRegion(region); 1.5791 + } 1.5792 +private: 1.5793 + PresShell* mShell; 1.5794 + nsIFrame* mFrame; 1.5795 +}; 1.5796 + 1.5797 +void 1.5798 +PresShell::RestyleShadowRoot(ShadowRoot* aShadowRoot) 1.5799 +{ 1.5800 + // Mark the children of the ShadowRoot as style changed but not 1.5801 + // the ShadowRoot itself because it is a document fragment and does not 1.5802 + // have a frame. 1.5803 + ExplicitChildIterator iterator(aShadowRoot); 1.5804 + for (nsIContent* child = iterator.GetNextChild(); 1.5805 + child; 1.5806 + child = iterator.GetNextChild()) { 1.5807 + if (child->IsElement()) { 1.5808 + mChangedScopeStyleRoots.AppendElement(child->AsElement()); 1.5809 + } 1.5810 + } 1.5811 +} 1.5812 + 1.5813 +void 1.5814 +PresShell::Paint(nsView* aViewToPaint, 1.5815 + const nsRegion& aDirtyRegion, 1.5816 + uint32_t aFlags) 1.5817 +{ 1.5818 + PROFILER_LABEL("Paint", "PresShell::Paint"); 1.5819 + NS_ASSERTION(!mIsDestroying, "painting a destroyed PresShell"); 1.5820 + NS_ASSERTION(aViewToPaint, "null view"); 1.5821 + 1.5822 + MOZ_ASSERT(!mImageVisibilityVisited, "should have been cleared"); 1.5823 + 1.5824 + if (!mIsActive || mIsZombie) { 1.5825 + return; 1.5826 + } 1.5827 + 1.5828 + nsPresContext* presContext = GetPresContext(); 1.5829 + AUTO_LAYOUT_PHASE_ENTRY_POINT(presContext, Paint); 1.5830 + 1.5831 + nsIFrame* frame = aViewToPaint->GetFrame(); 1.5832 + 1.5833 + bool isRetainingManager; 1.5834 + LayerManager* layerManager = 1.5835 + aViewToPaint->GetWidget()->GetLayerManager(&isRetainingManager); 1.5836 + NS_ASSERTION(layerManager, "Must be in paint event"); 1.5837 + bool shouldInvalidate = layerManager->NeedsWidgetInvalidation(); 1.5838 + 1.5839 + nsAutoNotifyDidPaint notifyDidPaint(this, aFlags); 1.5840 + AutoUpdateHitRegion updateHitRegion(this, frame); 1.5841 + 1.5842 + // Whether or not we should set first paint when painting is 1.5843 + // suppressed is debatable. For now we'll do it because 1.5844 + // B2G relies on first paint to configure the viewport and 1.5845 + // we only want to do that when we have real content to paint. 1.5846 + // See Bug 798245 1.5847 + if (mIsFirstPaint && !mPaintingSuppressed) { 1.5848 + layerManager->SetIsFirstPaint(); 1.5849 + mIsFirstPaint = false; 1.5850 + } 1.5851 + 1.5852 + layerManager->BeginTransaction(); 1.5853 + 1.5854 + if (frame && isRetainingManager) { 1.5855 + // Try to do an empty transaction, if the frame tree does not 1.5856 + // need to be updated. Do not try to do an empty transaction on 1.5857 + // a non-retained layer manager (like the BasicLayerManager that 1.5858 + // draws the window title bar on Mac), because a) it won't work 1.5859 + // and b) below we don't want to clear NS_FRAME_UPDATE_LAYER_TREE, 1.5860 + // that will cause us to forget to update the real layer manager! 1.5861 + 1.5862 + if (!(aFlags & PAINT_LAYERS)) { 1.5863 + if (layerManager->EndEmptyTransaction()) { 1.5864 + return; 1.5865 + } 1.5866 + NS_WARNING("Must complete empty transaction when compositing!"); 1.5867 + } 1.5868 + 1.5869 + if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE) && 1.5870 + !mNextPaintCompressed) { 1.5871 + NotifySubDocInvalidationFunc computeInvalidFunc = 1.5872 + presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0; 1.5873 + bool computeInvalidRect = computeInvalidFunc || 1.5874 + (layerManager->GetBackendType() == LayersBackend::LAYERS_BASIC); 1.5875 + 1.5876 + nsAutoPtr<LayerProperties> props(computeInvalidRect ? 1.5877 + LayerProperties::CloneFrom(layerManager->GetRoot()) : 1.5878 + nullptr); 1.5879 + 1.5880 + if (layerManager->EndEmptyTransaction((aFlags & PAINT_COMPOSITE) ? 1.5881 + LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE)) { 1.5882 + nsIntRegion invalid; 1.5883 + if (props) { 1.5884 + invalid = props->ComputeDifferences(layerManager->GetRoot(), computeInvalidFunc); 1.5885 + } else { 1.5886 + LayerProperties::ClearInvalidations(layerManager->GetRoot()); 1.5887 + } 1.5888 + if (props) { 1.5889 + if (!invalid.IsEmpty()) { 1.5890 + nsIntRect bounds = invalid.GetBounds(); 1.5891 + nsRect rect(presContext->DevPixelsToAppUnits(bounds.x), 1.5892 + presContext->DevPixelsToAppUnits(bounds.y), 1.5893 + presContext->DevPixelsToAppUnits(bounds.width), 1.5894 + presContext->DevPixelsToAppUnits(bounds.height)); 1.5895 + if (shouldInvalidate) { 1.5896 + aViewToPaint->GetViewManager()->InvalidateViewNoSuppression(aViewToPaint, rect); 1.5897 + } 1.5898 + presContext->NotifyInvalidation(bounds, 0); 1.5899 + } 1.5900 + } else if (shouldInvalidate) { 1.5901 + aViewToPaint->GetViewManager()->InvalidateView(aViewToPaint); 1.5902 + } 1.5903 + 1.5904 + frame->UpdatePaintCountForPaintedPresShells(); 1.5905 + return; 1.5906 + } 1.5907 + } 1.5908 + frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE); 1.5909 + } 1.5910 + if (frame) { 1.5911 + frame->ClearPresShellsFromLastPaint(); 1.5912 + } 1.5913 + 1.5914 + nscolor bgcolor = ComputeBackstopColor(aViewToPaint); 1.5915 + uint32_t flags = nsLayoutUtils::PAINT_WIDGET_LAYERS | nsLayoutUtils::PAINT_EXISTING_TRANSACTION; 1.5916 + if (!(aFlags & PAINT_COMPOSITE)) { 1.5917 + flags |= nsLayoutUtils::PAINT_NO_COMPOSITE; 1.5918 + } 1.5919 + if (mNextPaintCompressed) { 1.5920 + flags |= nsLayoutUtils::PAINT_COMPRESSED; 1.5921 + mNextPaintCompressed = false; 1.5922 + } 1.5923 + 1.5924 + if (frame) { 1.5925 + // We can paint directly into the widget using its layer manager. 1.5926 + nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor, flags); 1.5927 + return; 1.5928 + } 1.5929 + 1.5930 + nsRefPtr<ColorLayer> root = layerManager->CreateColorLayer(); 1.5931 + if (root) { 1.5932 + nsPresContext* pc = GetPresContext(); 1.5933 + nsIntRect bounds = 1.5934 + pc->GetVisibleArea().ToOutsidePixels(pc->AppUnitsPerDevPixel()); 1.5935 + bgcolor = NS_ComposeColors(bgcolor, mCanvasBackgroundColor); 1.5936 + root->SetColor(bgcolor); 1.5937 + root->SetVisibleRegion(bounds); 1.5938 + layerManager->SetRoot(root); 1.5939 + } 1.5940 + layerManager->EndTransaction(nullptr, nullptr, (aFlags & PAINT_COMPOSITE) ? 1.5941 + LayerManager::END_DEFAULT : LayerManager::END_NO_COMPOSITE); 1.5942 +} 1.5943 + 1.5944 +// static 1.5945 +void 1.5946 +nsIPresShell::SetCapturingContent(nsIContent* aContent, uint8_t aFlags) 1.5947 +{ 1.5948 + // If capture was set for pointer lock, don't unlock unless we are coming 1.5949 + // out of pointer lock explicitly. 1.5950 + if (!aContent && gCaptureInfo.mPointerLock && 1.5951 + !(aFlags & CAPTURE_POINTERLOCK)) { 1.5952 + return; 1.5953 + } 1.5954 + 1.5955 + NS_IF_RELEASE(gCaptureInfo.mContent); 1.5956 + 1.5957 + // only set capturing content if allowed or the CAPTURE_IGNOREALLOWED or 1.5958 + // CAPTURE_POINTERLOCK flags are used. 1.5959 + if ((aFlags & CAPTURE_IGNOREALLOWED) || gCaptureInfo.mAllowed || 1.5960 + (aFlags & CAPTURE_POINTERLOCK)) { 1.5961 + if (aContent) { 1.5962 + NS_ADDREF(gCaptureInfo.mContent = aContent); 1.5963 + } 1.5964 + // CAPTURE_POINTERLOCK is the same as CAPTURE_RETARGETTOELEMENT & CAPTURE_IGNOREALLOWED 1.5965 + gCaptureInfo.mRetargetToElement = ((aFlags & CAPTURE_RETARGETTOELEMENT) != 0) || 1.5966 + ((aFlags & CAPTURE_POINTERLOCK) != 0); 1.5967 + gCaptureInfo.mPreventDrag = (aFlags & CAPTURE_PREVENTDRAG) != 0; 1.5968 + gCaptureInfo.mPointerLock = (aFlags & CAPTURE_POINTERLOCK) != 0; 1.5969 + } 1.5970 +} 1.5971 + 1.5972 +/* static */ void 1.5973 +nsIPresShell::SetPointerCapturingContent(uint32_t aPointerId, nsIContent* aContent) 1.5974 +{ 1.5975 + nsIContent* content = GetPointerCapturingContent(aPointerId); 1.5976 + 1.5977 + PointerInfo* pointerInfo = nullptr; 1.5978 + if (!content && gActivePointersIds->Get(aPointerId, &pointerInfo) && 1.5979 + pointerInfo && 1.5980 + nsIDOMMouseEvent::MOZ_SOURCE_MOUSE == pointerInfo->mPointerType) { 1.5981 + SetCapturingContent(aContent, CAPTURE_PREVENTDRAG); 1.5982 + } 1.5983 + 1.5984 + if (content) { 1.5985 + // Releasing capture for given pointer. 1.5986 + gPointerCaptureList->Remove(aPointerId); 1.5987 + DispatchGotOrLostPointerCaptureEvent(false, aPointerId, content); 1.5988 + // Need to check the state because a lostpointercapture listener 1.5989 + // may have called SetPointerCapture 1.5990 + if (GetPointerCapturingContent(aPointerId)) { 1.5991 + return; 1.5992 + } 1.5993 + } 1.5994 + 1.5995 + gPointerCaptureList->Put(aPointerId, aContent); 1.5996 + DispatchGotOrLostPointerCaptureEvent(true, aPointerId, aContent); 1.5997 +} 1.5998 + 1.5999 +/* static */ void 1.6000 +nsIPresShell::ReleasePointerCapturingContent(uint32_t aPointerId, nsIContent* aContent) 1.6001 +{ 1.6002 + if (gActivePointersIds->Get(aPointerId)) { 1.6003 + SetCapturingContent(nullptr, CAPTURE_PREVENTDRAG); 1.6004 + } 1.6005 + 1.6006 + // Releasing capture for given pointer. 1.6007 + gPointerCaptureList->Remove(aPointerId); 1.6008 + 1.6009 + DispatchGotOrLostPointerCaptureEvent(false, aPointerId, aContent); 1.6010 +} 1.6011 + 1.6012 +/* static */ nsIContent* 1.6013 +nsIPresShell::GetPointerCapturingContent(uint32_t aPointerId) 1.6014 +{ 1.6015 + return gPointerCaptureList->GetWeak(aPointerId); 1.6016 +} 1.6017 + 1.6018 +/* static */ bool 1.6019 +nsIPresShell::GetPointerInfo(uint32_t aPointerId, bool& aActiveState) 1.6020 +{ 1.6021 + PointerInfo* pointerInfo = nullptr; 1.6022 + if (gActivePointersIds->Get(aPointerId, &pointerInfo) && pointerInfo) { 1.6023 + aActiveState = pointerInfo->mActiveState; 1.6024 + return true; 1.6025 + } 1.6026 + return false; 1.6027 +} 1.6028 + 1.6029 +void 1.6030 +PresShell::UpdateActivePointerState(WidgetGUIEvent* aEvent) 1.6031 +{ 1.6032 + switch (aEvent->message) { 1.6033 + case NS_MOUSE_ENTER: 1.6034 + // In this case we have to know information about available mouse pointers 1.6035 + if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) { 1.6036 + gActivePointersIds->Put(mouseEvent->pointerId, new PointerInfo(false, mouseEvent->inputSource)); 1.6037 + } 1.6038 + break; 1.6039 + case NS_POINTER_DOWN: 1.6040 + // In this case we switch pointer to active state 1.6041 + if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) { 1.6042 + gActivePointersIds->Put(pointerEvent->pointerId, new PointerInfo(true, pointerEvent->inputSource)); 1.6043 + } 1.6044 + break; 1.6045 + case NS_POINTER_UP: 1.6046 + // In this case we remove information about pointer or turn off active state 1.6047 + if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) { 1.6048 + if(pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) { 1.6049 + gActivePointersIds->Put(pointerEvent->pointerId, new PointerInfo(false, pointerEvent->inputSource)); 1.6050 + } else { 1.6051 + gActivePointersIds->Remove(pointerEvent->pointerId); 1.6052 + } 1.6053 + } 1.6054 + break; 1.6055 + case NS_MOUSE_EXIT: 1.6056 + // In this case we have to remove information about disappeared mouse pointers 1.6057 + if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) { 1.6058 + gActivePointersIds->Remove(mouseEvent->pointerId); 1.6059 + } 1.6060 + break; 1.6061 + } 1.6062 +} 1.6063 + 1.6064 +nsIContent* 1.6065 +PresShell::GetCurrentEventContent() 1.6066 +{ 1.6067 + if (mCurrentEventContent && 1.6068 + mCurrentEventContent->GetCurrentDoc() != mDocument) { 1.6069 + mCurrentEventContent = nullptr; 1.6070 + mCurrentEventFrame = nullptr; 1.6071 + } 1.6072 + return mCurrentEventContent; 1.6073 +} 1.6074 + 1.6075 +nsIFrame* 1.6076 +PresShell::GetCurrentEventFrame() 1.6077 +{ 1.6078 + if (MOZ_UNLIKELY(mIsDestroying)) { 1.6079 + return nullptr; 1.6080 + } 1.6081 + 1.6082 + // GetCurrentEventContent() makes sure the content is still in the 1.6083 + // same document that this pres shell belongs to. If not, then the 1.6084 + // frame shouldn't get an event, nor should we even assume its safe 1.6085 + // to try and find the frame. 1.6086 + nsIContent* content = GetCurrentEventContent(); 1.6087 + if (!mCurrentEventFrame && content) { 1.6088 + mCurrentEventFrame = content->GetPrimaryFrame(); 1.6089 + MOZ_ASSERT(!mCurrentEventFrame || 1.6090 + mCurrentEventFrame->PresContext()->GetPresShell() == this); 1.6091 + } 1.6092 + return mCurrentEventFrame; 1.6093 +} 1.6094 + 1.6095 +nsIFrame* 1.6096 +PresShell::GetEventTargetFrame() 1.6097 +{ 1.6098 + return GetCurrentEventFrame(); 1.6099 +} 1.6100 + 1.6101 +already_AddRefed<nsIContent> 1.6102 +PresShell::GetEventTargetContent(WidgetEvent* aEvent) 1.6103 +{ 1.6104 + nsCOMPtr<nsIContent> content = GetCurrentEventContent(); 1.6105 + if (!content) { 1.6106 + nsIFrame* currentEventFrame = GetCurrentEventFrame(); 1.6107 + if (currentEventFrame) { 1.6108 + currentEventFrame->GetContentForEvent(aEvent, getter_AddRefs(content)); 1.6109 + NS_ASSERTION(!content || content->GetCurrentDoc() == mDocument, 1.6110 + "handing out content from a different doc"); 1.6111 + } 1.6112 + } 1.6113 + return content.forget(); 1.6114 +} 1.6115 + 1.6116 +void 1.6117 +PresShell::PushCurrentEventInfo(nsIFrame* aFrame, nsIContent* aContent) 1.6118 +{ 1.6119 + if (mCurrentEventFrame || mCurrentEventContent) { 1.6120 + mCurrentEventFrameStack.InsertElementAt(0, mCurrentEventFrame); 1.6121 + mCurrentEventContentStack.InsertObjectAt(mCurrentEventContent, 0); 1.6122 + } 1.6123 + mCurrentEventFrame = aFrame; 1.6124 + mCurrentEventContent = aContent; 1.6125 +} 1.6126 + 1.6127 +void 1.6128 +PresShell::PopCurrentEventInfo() 1.6129 +{ 1.6130 + mCurrentEventFrame = nullptr; 1.6131 + mCurrentEventContent = nullptr; 1.6132 + 1.6133 + if (0 != mCurrentEventFrameStack.Length()) { 1.6134 + mCurrentEventFrame = mCurrentEventFrameStack.ElementAt(0); 1.6135 + mCurrentEventFrameStack.RemoveElementAt(0); 1.6136 + mCurrentEventContent = mCurrentEventContentStack.ObjectAt(0); 1.6137 + mCurrentEventContentStack.RemoveObjectAt(0); 1.6138 + 1.6139 + // Don't use it if it has moved to a different document. 1.6140 + if (mCurrentEventContent && 1.6141 + mCurrentEventContent->GetCurrentDoc() != mDocument) { 1.6142 + mCurrentEventContent = nullptr; 1.6143 + mCurrentEventFrame = nullptr; 1.6144 + } 1.6145 + } 1.6146 +} 1.6147 + 1.6148 +bool PresShell::InZombieDocument(nsIContent *aContent) 1.6149 +{ 1.6150 + // If a content node points to a null document, or the document is not 1.6151 + // attached to a window, then it is possibly in a zombie document, 1.6152 + // about to be replaced by a newly loading document. 1.6153 + // Such documents cannot handle DOM events. 1.6154 + // It might actually be in a node not attached to any document, 1.6155 + // in which case there is not parent presshell to retarget it to. 1.6156 + nsIDocument *doc = aContent->GetDocument(); 1.6157 + return !doc || !doc->GetWindow(); 1.6158 +} 1.6159 + 1.6160 +already_AddRefed<nsPIDOMWindow> 1.6161 +PresShell::GetRootWindow() 1.6162 +{ 1.6163 + nsCOMPtr<nsPIDOMWindow> window = 1.6164 + do_QueryInterface(mDocument->GetWindow()); 1.6165 + if (window) { 1.6166 + nsCOMPtr<nsPIDOMWindow> rootWindow = window->GetPrivateRoot(); 1.6167 + NS_ASSERTION(rootWindow, "nsPIDOMWindow::GetPrivateRoot() returns NULL"); 1.6168 + return rootWindow.forget(); 1.6169 + } 1.6170 + 1.6171 + // If we don't have DOM window, we're zombie, we should find the root window 1.6172 + // with our parent shell. 1.6173 + nsCOMPtr<nsIPresShell> parent = GetParentPresShellForEventHandling(); 1.6174 + NS_ENSURE_TRUE(parent, nullptr); 1.6175 + return parent->GetRootWindow(); 1.6176 +} 1.6177 + 1.6178 +already_AddRefed<nsIPresShell> 1.6179 +PresShell::GetParentPresShellForEventHandling() 1.6180 +{ 1.6181 + NS_ENSURE_TRUE(mPresContext, nullptr); 1.6182 + 1.6183 + // Now, find the parent pres shell and send the event there 1.6184 + nsCOMPtr<nsIDocShellTreeItem> treeItem = mPresContext->GetDocShell(); 1.6185 + if (!treeItem) { 1.6186 + treeItem = mForwardingContainer.get(); 1.6187 + } 1.6188 + 1.6189 + // Might have gone away, or never been around to start with 1.6190 + NS_ENSURE_TRUE(treeItem, nullptr); 1.6191 + 1.6192 + nsCOMPtr<nsIDocShellTreeItem> parentTreeItem; 1.6193 + treeItem->GetParent(getter_AddRefs(parentTreeItem)); 1.6194 + nsCOMPtr<nsIDocShell> parentDocShell = do_QueryInterface(parentTreeItem); 1.6195 + NS_ENSURE_TRUE(parentDocShell && treeItem != parentTreeItem, nullptr); 1.6196 + 1.6197 + nsCOMPtr<nsIPresShell> parentPresShell = parentDocShell->GetPresShell(); 1.6198 + return parentPresShell.forget(); 1.6199 +} 1.6200 + 1.6201 +nsresult 1.6202 +PresShell::RetargetEventToParent(WidgetGUIEvent* aEvent, 1.6203 + nsEventStatus* aEventStatus) 1.6204 +{ 1.6205 + // Send this events straight up to the parent pres shell. 1.6206 + // We do this for keystroke events in zombie documents or if either a frame 1.6207 + // or a root content is not present. 1.6208 + // That way at least the UI key bindings can work. 1.6209 + 1.6210 + nsCOMPtr<nsIPresShell> kungFuDeathGrip(this); 1.6211 + nsCOMPtr<nsIPresShell> parentPresShell = GetParentPresShellForEventHandling(); 1.6212 + NS_ENSURE_TRUE(parentPresShell, NS_ERROR_FAILURE); 1.6213 + 1.6214 + // Fake the event as though it's from the parent pres shell's root frame. 1.6215 + return parentPresShell->HandleEvent(parentPresShell->GetRootFrame(), aEvent, true, aEventStatus); 1.6216 +} 1.6217 + 1.6218 +void 1.6219 +PresShell::DisableNonTestMouseEvents(bool aDisable) 1.6220 +{ 1.6221 + sDisableNonTestMouseEvents = aDisable; 1.6222 +} 1.6223 + 1.6224 +already_AddRefed<nsPIDOMWindow> 1.6225 +PresShell::GetFocusedDOMWindowInOurWindow() 1.6226 +{ 1.6227 + nsCOMPtr<nsPIDOMWindow> rootWindow = GetRootWindow(); 1.6228 + NS_ENSURE_TRUE(rootWindow, nullptr); 1.6229 + nsCOMPtr<nsPIDOMWindow> focusedWindow; 1.6230 + nsFocusManager::GetFocusedDescendant(rootWindow, true, 1.6231 + getter_AddRefs(focusedWindow)); 1.6232 + return focusedWindow.forget(); 1.6233 +} 1.6234 + 1.6235 +void 1.6236 +PresShell::RecordMouseLocation(WidgetGUIEvent* aEvent) 1.6237 +{ 1.6238 + if (!mPresContext) 1.6239 + return; 1.6240 + 1.6241 + if (!mPresContext->IsRoot()) { 1.6242 + PresShell* rootPresShell = GetRootPresShell(); 1.6243 + if (rootPresShell) { 1.6244 + rootPresShell->RecordMouseLocation(aEvent); 1.6245 + } 1.6246 + return; 1.6247 + } 1.6248 + 1.6249 + if ((aEvent->message == NS_MOUSE_MOVE && 1.6250 + aEvent->AsMouseEvent()->reason == WidgetMouseEvent::eReal) || 1.6251 + aEvent->message == NS_MOUSE_ENTER || 1.6252 + aEvent->message == NS_MOUSE_BUTTON_DOWN || 1.6253 + aEvent->message == NS_MOUSE_BUTTON_UP) { 1.6254 + nsIFrame* rootFrame = GetRootFrame(); 1.6255 + if (!rootFrame) { 1.6256 + nsView* rootView = mViewManager->GetRootView(); 1.6257 + mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext, 1.6258 + aEvent->widget, LayoutDeviceIntPoint::ToUntyped(aEvent->refPoint), 1.6259 + rootView); 1.6260 + } else { 1.6261 + mMouseLocation = 1.6262 + nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame); 1.6263 + } 1.6264 +#ifdef DEBUG_MOUSE_LOCATION 1.6265 + if (aEvent->message == NS_MOUSE_ENTER) 1.6266 + printf("[ps=%p]got mouse enter for %p\n", 1.6267 + this, aEvent->widget); 1.6268 + printf("[ps=%p]setting mouse location to (%d,%d)\n", 1.6269 + this, mMouseLocation.x, mMouseLocation.y); 1.6270 +#endif 1.6271 + if (aEvent->message == NS_MOUSE_ENTER) 1.6272 + SynthesizeMouseMove(false); 1.6273 + } else if (aEvent->message == NS_MOUSE_EXIT) { 1.6274 + // Although we only care about the mouse moving into an area for which this 1.6275 + // pres shell doesn't receive mouse move events, we don't check which widget 1.6276 + // the mouse exit was for since this seems to vary by platform. Hopefully 1.6277 + // this won't matter at all since we'll get the mouse move or enter after 1.6278 + // the mouse exit when the mouse moves from one of our widgets into another. 1.6279 + mMouseLocation = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); 1.6280 +#ifdef DEBUG_MOUSE_LOCATION 1.6281 + printf("[ps=%p]got mouse exit for %p\n", 1.6282 + this, aEvent->widget); 1.6283 + printf("[ps=%p]clearing mouse location\n", 1.6284 + this); 1.6285 +#endif 1.6286 + } 1.6287 +} 1.6288 + 1.6289 +static void 1.6290 +EvictTouchPoint(nsRefPtr<dom::Touch>& aTouch, 1.6291 + nsIDocument* aLimitToDocument = nullptr) 1.6292 +{ 1.6293 + nsCOMPtr<nsINode> node(do_QueryInterface(aTouch->mTarget)); 1.6294 + if (node) { 1.6295 + nsIDocument* doc = node->GetCurrentDoc(); 1.6296 + if (doc && (!aLimitToDocument || aLimitToDocument == doc)) { 1.6297 + nsIPresShell* presShell = doc->GetShell(); 1.6298 + if (presShell) { 1.6299 + nsIFrame* frame = presShell->GetRootFrame(); 1.6300 + if (frame) { 1.6301 + nsPoint pt(aTouch->mRefPoint.x, aTouch->mRefPoint.y); 1.6302 + nsCOMPtr<nsIWidget> widget = frame->GetView()->GetNearestWidget(&pt); 1.6303 + if (widget) { 1.6304 + WidgetTouchEvent event(true, NS_TOUCH_END, widget); 1.6305 + event.widget = widget; 1.6306 + event.time = PR_IntervalNow(); 1.6307 + event.touches.AppendElement(aTouch); 1.6308 + nsEventStatus status; 1.6309 + widget->DispatchEvent(&event, status); 1.6310 + return; 1.6311 + } 1.6312 + } 1.6313 + } 1.6314 + } 1.6315 + } 1.6316 + if (!node || !aLimitToDocument || node->OwnerDoc() == aLimitToDocument) { 1.6317 + // We couldn't dispatch touchend. Remove the touch from gCaptureTouchList 1.6318 + // explicitly. 1.6319 + nsIPresShell::gCaptureTouchList->Remove(aTouch->Identifier()); 1.6320 + } 1.6321 +} 1.6322 + 1.6323 +static PLDHashOperator 1.6324 +AppendToTouchList(const uint32_t& aKey, nsRefPtr<dom::Touch>& aData, void *aTouchList) 1.6325 +{ 1.6326 + nsTArray< nsRefPtr<dom::Touch> >* touches = 1.6327 + static_cast<nsTArray< nsRefPtr<dom::Touch> >*>(aTouchList); 1.6328 + aData->mChanged = false; 1.6329 + touches->AppendElement(aData); 1.6330 + return PL_DHASH_NEXT; 1.6331 +} 1.6332 + 1.6333 +void 1.6334 +PresShell::EvictTouches() 1.6335 +{ 1.6336 + nsTArray< nsRefPtr<dom::Touch> > touches; 1.6337 + gCaptureTouchList->Enumerate(&AppendToTouchList, &touches); 1.6338 + for (uint32_t i = 0; i < touches.Length(); ++i) { 1.6339 + EvictTouchPoint(touches[i], mDocument); 1.6340 + } 1.6341 +} 1.6342 + 1.6343 +static PLDHashOperator 1.6344 +FindAnyTarget(const uint32_t& aKey, nsRefPtr<dom::Touch>& aData, 1.6345 + void* aAnyTarget) 1.6346 +{ 1.6347 + if (aData) { 1.6348 + dom::EventTarget* target = aData->Target(); 1.6349 + if (target) { 1.6350 + nsCOMPtr<nsIContent>* content = 1.6351 + static_cast<nsCOMPtr<nsIContent>*>(aAnyTarget); 1.6352 + *content = do_QueryInterface(target); 1.6353 + return PL_DHASH_STOP; 1.6354 + } 1.6355 + } 1.6356 + return PL_DHASH_NEXT; 1.6357 +} 1.6358 + 1.6359 +nsIFrame* GetNearestFrameContainingPresShell(nsIPresShell* aPresShell) 1.6360 +{ 1.6361 + nsView* view = aPresShell->GetViewManager()->GetRootView(); 1.6362 + while (view && !view->GetFrame()) { 1.6363 + view = view->GetParent(); 1.6364 + } 1.6365 + 1.6366 + nsIFrame* frame = nullptr; 1.6367 + if (view) { 1.6368 + frame = view->GetFrame(); 1.6369 + } 1.6370 + 1.6371 + return frame; 1.6372 +} 1.6373 + 1.6374 +static bool 1.6375 +FlushThrottledStyles(nsIDocument *aDocument, void *aData) 1.6376 +{ 1.6377 + nsIPresShell* shell = aDocument->GetShell(); 1.6378 + if (shell && shell->IsVisible()) { 1.6379 + nsPresContext* presContext = shell->GetPresContext(); 1.6380 + if (presContext) { 1.6381 + presContext->TransitionManager()->UpdateAllThrottledStyles(); 1.6382 + presContext->AnimationManager()->UpdateAllThrottledStyles(); 1.6383 + } 1.6384 + } 1.6385 + 1.6386 + return true; 1.6387 +} 1.6388 + 1.6389 +static nsresult 1.6390 +DispatchPointerFromMouseOrTouch(PresShell* aShell, 1.6391 + nsIFrame* aFrame, 1.6392 + WidgetGUIEvent* aEvent, 1.6393 + bool aDontRetargetEvents, 1.6394 + nsEventStatus* aStatus) 1.6395 +{ 1.6396 + uint32_t pointerMessage = 0; 1.6397 + if (aEvent->eventStructType == NS_MOUSE_EVENT) { 1.6398 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.6399 + // if it is not mouse then it is likely will come as touch event 1.6400 + if (!mouseEvent->convertToPointer) { 1.6401 + return NS_OK; 1.6402 + } 1.6403 + int16_t button = mouseEvent->button; 1.6404 + switch (mouseEvent->message) { 1.6405 + case NS_MOUSE_MOVE: 1.6406 + if (mouseEvent->buttons == 0) { 1.6407 + button = -1; 1.6408 + } 1.6409 + pointerMessage = NS_POINTER_MOVE; 1.6410 + break; 1.6411 + case NS_MOUSE_BUTTON_UP: 1.6412 + pointerMessage = NS_POINTER_UP; 1.6413 + break; 1.6414 + case NS_MOUSE_BUTTON_DOWN: 1.6415 + pointerMessage = NS_POINTER_DOWN; 1.6416 + break; 1.6417 + default: 1.6418 + return NS_OK; 1.6419 + } 1.6420 + 1.6421 + WidgetPointerEvent event(*mouseEvent); 1.6422 + event.message = pointerMessage; 1.6423 + event.button = button; 1.6424 + event.pressure = event.buttons ? 1.6425 + mouseEvent->pressure ? mouseEvent->pressure : 0.5f : 1.6426 + 0.0f; 1.6427 + event.convertToPointer = mouseEvent->convertToPointer = false; 1.6428 + aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus); 1.6429 + } else if (aEvent->eventStructType == NS_TOUCH_EVENT) { 1.6430 + WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); 1.6431 + // loop over all touches and dispatch pointer events on each touch 1.6432 + // copy the event 1.6433 + switch (touchEvent->message) { 1.6434 + case NS_TOUCH_MOVE: 1.6435 + pointerMessage = NS_POINTER_MOVE; 1.6436 + break; 1.6437 + case NS_TOUCH_END: 1.6438 + pointerMessage = NS_POINTER_UP; 1.6439 + break; 1.6440 + case NS_TOUCH_START: 1.6441 + pointerMessage = NS_POINTER_DOWN; 1.6442 + break; 1.6443 + case NS_TOUCH_CANCEL: 1.6444 + pointerMessage = NS_POINTER_CANCEL; 1.6445 + break; 1.6446 + default: 1.6447 + return NS_OK; 1.6448 + } 1.6449 + 1.6450 + for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) { 1.6451 + mozilla::dom::Touch* touch = touchEvent->touches[i]; 1.6452 + if (!touch || !touch->convertToPointer) { 1.6453 + continue; 1.6454 + } 1.6455 + 1.6456 + WidgetPointerEvent event(touchEvent->mFlags.mIsTrusted, pointerMessage, touchEvent->widget); 1.6457 + event.isPrimary = i == 0; 1.6458 + event.pointerId = touch->Identifier(); 1.6459 + event.refPoint.x = touch->mRefPoint.x; 1.6460 + event.refPoint.y = touch->mRefPoint.y; 1.6461 + event.modifiers = touchEvent->modifiers; 1.6462 + event.width = touch->RadiusX(); 1.6463 + event.height = touch->RadiusY(); 1.6464 + event.tiltX = touch->tiltX; 1.6465 + event.tiltY = touch->tiltY; 1.6466 + event.time = touchEvent->time; 1.6467 + event.mFlags = touchEvent->mFlags; 1.6468 + event.button = WidgetMouseEvent::eLeftButton; 1.6469 + event.buttons = WidgetMouseEvent::eLeftButtonFlag; 1.6470 + event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_TOUCH; 1.6471 + event.convertToPointer = touch->convertToPointer = false; 1.6472 + aShell->HandleEvent(aFrame, &event, aDontRetargetEvents, aStatus); 1.6473 + } 1.6474 + } 1.6475 + return NS_OK; 1.6476 +} 1.6477 + 1.6478 +class ReleasePointerCaptureCaller 1.6479 +{ 1.6480 +public: 1.6481 + ReleasePointerCaptureCaller() : 1.6482 + mPointerId(0), 1.6483 + mContent(nullptr) 1.6484 + { 1.6485 + } 1.6486 + ~ReleasePointerCaptureCaller() 1.6487 + { 1.6488 + if (mContent) { 1.6489 + nsIPresShell::ReleasePointerCapturingContent(mPointerId, mContent); 1.6490 + } 1.6491 + } 1.6492 + void SetTarget(uint32_t aPointerId, nsIContent* aContent) 1.6493 + { 1.6494 + mPointerId = aPointerId; 1.6495 + mContent = aContent; 1.6496 + } 1.6497 + 1.6498 +private: 1.6499 + int32_t mPointerId; 1.6500 + nsCOMPtr<nsIContent> mContent; 1.6501 +}; 1.6502 + 1.6503 +nsresult 1.6504 +PresShell::HandleEvent(nsIFrame* aFrame, 1.6505 + WidgetGUIEvent* aEvent, 1.6506 + bool aDontRetargetEvents, 1.6507 + nsEventStatus* aEventStatus) 1.6508 +{ 1.6509 +#ifdef MOZ_TASK_TRACER 1.6510 + // Make touch events, mouse events and hardware key events to be the source 1.6511 + // events of TaskTracer, and originate the rest correlation tasks from here. 1.6512 + SourceEventType type = SourceEventType::UNKNOWN; 1.6513 + if (WidgetTouchEvent* inputEvent = aEvent->AsTouchEvent()) { 1.6514 + type = SourceEventType::TOUCH; 1.6515 + } else if (WidgetMouseEvent* inputEvent = aEvent->AsMouseEvent()) { 1.6516 + type = SourceEventType::MOUSE; 1.6517 + } else if (WidgetKeyboardEvent* inputEvent = aEvent->AsKeyboardEvent()) { 1.6518 + type = SourceEventType::KEY; 1.6519 + } 1.6520 + AutoSourceEvent taskTracerEvent(type); 1.6521 +#endif 1.6522 + 1.6523 + if (sPointerEventEnabled) { 1.6524 + DispatchPointerFromMouseOrTouch(this, aFrame, aEvent, aDontRetargetEvents, aEventStatus); 1.6525 + } 1.6526 + 1.6527 + NS_ASSERTION(aFrame, "null frame"); 1.6528 + 1.6529 + if (mIsDestroying || 1.6530 + (sDisableNonTestMouseEvents && !aEvent->mFlags.mIsSynthesizedForTests && 1.6531 + aEvent->HasMouseEventMessage())) { 1.6532 + return NS_OK; 1.6533 + } 1.6534 + 1.6535 + RecordMouseLocation(aEvent); 1.6536 + if (sPointerEventEnabled) { 1.6537 + UpdateActivePointerState(aEvent); 1.6538 + } 1.6539 + 1.6540 + if (!nsContentUtils::IsSafeToRunScript()) 1.6541 + return NS_OK; 1.6542 + 1.6543 + nsIContent* capturingContent = 1.6544 + (aEvent->HasMouseEventMessage() || 1.6545 + aEvent->eventStructType == NS_WHEEL_EVENT ? GetCapturingContent() : 1.6546 + nullptr); 1.6547 + 1.6548 + nsCOMPtr<nsIDocument> retargetEventDoc; 1.6549 + if (!aDontRetargetEvents) { 1.6550 + // key and IME related events should not cross top level window boundary. 1.6551 + // Basically, such input events should be fired only on focused widget. 1.6552 + // However, some IMEs might need to clean up composition after focused 1.6553 + // window is deactivated. And also some tests on MozMill want to test key 1.6554 + // handling on deactivated window because MozMill window can be activated 1.6555 + // during tests. So, there is no merit the events should be redirected to 1.6556 + // active window. So, the events should be handled on the last focused 1.6557 + // content in the last focused DOM window in same top level window. 1.6558 + // Note, if no DOM window has been focused yet, we can discard the events. 1.6559 + if (aEvent->IsTargetedAtFocusedWindow()) { 1.6560 + nsCOMPtr<nsPIDOMWindow> window = GetFocusedDOMWindowInOurWindow(); 1.6561 + // No DOM window in same top level window has not been focused yet, 1.6562 + // discard the events. 1.6563 + if (!window) { 1.6564 + return NS_OK; 1.6565 + } 1.6566 + 1.6567 + retargetEventDoc = window->GetExtantDoc(); 1.6568 + if (!retargetEventDoc) 1.6569 + return NS_OK; 1.6570 + } else if (capturingContent) { 1.6571 + // if the mouse is being captured then retarget the mouse event at the 1.6572 + // document that is being captured. 1.6573 + retargetEventDoc = capturingContent->GetCurrentDoc(); 1.6574 +#ifdef ANDROID 1.6575 + } else if (aEvent->eventStructType == NS_TOUCH_EVENT) { 1.6576 + retargetEventDoc = GetTouchEventTargetDocument(); 1.6577 +#endif 1.6578 + } 1.6579 + 1.6580 + if (retargetEventDoc) { 1.6581 + nsCOMPtr<nsIPresShell> presShell = retargetEventDoc->GetShell(); 1.6582 + if (!presShell) 1.6583 + return NS_OK; 1.6584 + 1.6585 + if (presShell != this) { 1.6586 + nsIFrame* frame = presShell->GetRootFrame(); 1.6587 + if (!frame) { 1.6588 + if (aEvent->message == NS_QUERY_TEXT_CONTENT || 1.6589 + aEvent->IsContentCommandEvent()) { 1.6590 + return NS_OK; 1.6591 + } 1.6592 + 1.6593 + frame = GetNearestFrameContainingPresShell(presShell); 1.6594 + } 1.6595 + 1.6596 + if (!frame) 1.6597 + return NS_OK; 1.6598 + 1.6599 + nsCOMPtr<nsIPresShell> shell = frame->PresContext()->GetPresShell(); 1.6600 + return shell->HandleEvent(frame, aEvent, true, aEventStatus); 1.6601 + } 1.6602 + } 1.6603 + } 1.6604 + 1.6605 + if (aEvent->eventStructType == NS_KEY_EVENT && 1.6606 + mDocument && mDocument->EventHandlingSuppressed()) { 1.6607 + if (aEvent->message == NS_KEY_DOWN) { 1.6608 + mNoDelayedKeyEvents = true; 1.6609 + } else if (!mNoDelayedKeyEvents) { 1.6610 + DelayedEvent* event = new DelayedKeyEvent(aEvent->AsKeyboardEvent()); 1.6611 + if (!mDelayedEvents.AppendElement(event)) { 1.6612 + delete event; 1.6613 + } 1.6614 + } 1.6615 + return NS_OK; 1.6616 + } 1.6617 + 1.6618 + nsIFrame* frame = aFrame; 1.6619 + 1.6620 + if (aEvent->IsUsingCoordinates()) { 1.6621 + ReleasePointerCaptureCaller releasePointerCaptureCaller; 1.6622 + if (nsLayoutUtils::AreAsyncAnimationsEnabled() && mDocument) { 1.6623 + if (aEvent->eventStructType == NS_TOUCH_EVENT) { 1.6624 + nsIDocument::UnlockPointer(); 1.6625 + } 1.6626 + 1.6627 + { // scope for scriptBlocker. 1.6628 + nsAutoScriptBlocker scriptBlocker; 1.6629 + GetRootPresShell()->GetDocument()-> 1.6630 + EnumerateSubDocuments(FlushThrottledStyles, nullptr); 1.6631 + } 1.6632 + frame = GetNearestFrameContainingPresShell(this); 1.6633 + } 1.6634 + 1.6635 + NS_WARN_IF_FALSE(frame, "Nothing to handle this event!"); 1.6636 + if (!frame) 1.6637 + return NS_OK; 1.6638 + 1.6639 + nsPresContext* framePresContext = frame->PresContext(); 1.6640 + nsPresContext* rootPresContext = framePresContext->GetRootPresContext(); 1.6641 + NS_ASSERTION(rootPresContext == mPresContext->GetRootPresContext(), 1.6642 + "How did we end up outside the connected prescontext/viewmanager hierarchy?"); 1.6643 + // If we aren't starting our event dispatch from the root frame of the root prescontext, 1.6644 + // then someone must be capturing the mouse. In that case we don't want to search the popup 1.6645 + // list. 1.6646 + if (framePresContext == rootPresContext && 1.6647 + frame == mFrameConstructor->GetRootFrame()) { 1.6648 + nsIFrame* popupFrame = 1.6649 + nsLayoutUtils::GetPopupFrameForEventCoordinates(rootPresContext, aEvent); 1.6650 + // If the popupFrame is an ancestor of the 'frame', the frame should 1.6651 + // handle the event, otherwise, the popup should handle it. 1.6652 + if (popupFrame && 1.6653 + !nsContentUtils::ContentIsCrossDocDescendantOf( 1.6654 + framePresContext->GetPresShell()->GetDocument(), 1.6655 + popupFrame->GetContent())) { 1.6656 + frame = popupFrame; 1.6657 + } 1.6658 + } 1.6659 + 1.6660 + bool captureRetarget = false; 1.6661 + if (capturingContent) { 1.6662 + // If a capture is active, determine if the docshell is visible. If not, 1.6663 + // clear the capture and target the mouse event normally instead. This 1.6664 + // would occur if the mouse button is held down while a tab change occurs. 1.6665 + // If the docshell is visible, look for a scrolling container. 1.6666 + bool vis; 1.6667 + nsCOMPtr<nsIBaseWindow> baseWin = 1.6668 + do_QueryInterface(mPresContext->GetContainerWeak()); 1.6669 + if (baseWin && NS_SUCCEEDED(baseWin->GetVisibility(&vis)) && vis) { 1.6670 + captureRetarget = gCaptureInfo.mRetargetToElement; 1.6671 + if (!captureRetarget) { 1.6672 + // A check was already done above to ensure that capturingContent is 1.6673 + // in this presshell. 1.6674 + NS_ASSERTION(capturingContent->GetCurrentDoc() == GetDocument(), 1.6675 + "Unexpected document"); 1.6676 + nsIFrame* captureFrame = capturingContent->GetPrimaryFrame(); 1.6677 + if (captureFrame) { 1.6678 + if (capturingContent->Tag() == nsGkAtoms::select && 1.6679 + capturingContent->IsHTML()) { 1.6680 + // a dropdown <select> has a child in its selectPopupList and we should 1.6681 + // capture on that instead. 1.6682 + nsIFrame* childFrame = captureFrame->GetChildList(nsIFrame::kSelectPopupList).FirstChild(); 1.6683 + if (childFrame) { 1.6684 + captureFrame = childFrame; 1.6685 + } 1.6686 + } 1.6687 + 1.6688 + // scrollable frames should use the scrolling container as 1.6689 + // the root instead of the document 1.6690 + nsIScrollableFrame* scrollFrame = do_QueryFrame(captureFrame); 1.6691 + if (scrollFrame) { 1.6692 + frame = scrollFrame->GetScrolledFrame(); 1.6693 + } 1.6694 + } 1.6695 + } 1.6696 + } 1.6697 + else { 1.6698 + ClearMouseCapture(nullptr); 1.6699 + capturingContent = nullptr; 1.6700 + } 1.6701 + } 1.6702 + 1.6703 + // all touch events except for touchstart use a captured target 1.6704 + if (aEvent->eventStructType == NS_TOUCH_EVENT && 1.6705 + aEvent->message != NS_TOUCH_START) { 1.6706 + captureRetarget = true; 1.6707 + } 1.6708 + 1.6709 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.6710 + bool isWindowLevelMouseExit = (aEvent->message == NS_MOUSE_EXIT) && 1.6711 + (mouseEvent && mouseEvent->exit == WidgetMouseEvent::eTopLevel); 1.6712 + 1.6713 + // Get the frame at the event point. However, don't do this if we're 1.6714 + // capturing and retargeting the event because the captured frame will 1.6715 + // be used instead below. Also keep using the root frame if we're dealing 1.6716 + // with a window-level mouse exit event since we want to start sending 1.6717 + // mouse out events at the root EventStateManager. 1.6718 + if (!captureRetarget && !isWindowLevelMouseExit) { 1.6719 + nsPoint eventPoint; 1.6720 + uint32_t flags = 0; 1.6721 + if (aEvent->message == NS_TOUCH_START) { 1.6722 + flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME; 1.6723 + WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); 1.6724 + // if this is a continuing session, ensure that all these events are 1.6725 + // in the same document by taking the target of the events already in 1.6726 + // the capture list 1.6727 + nsCOMPtr<nsIContent> anyTarget; 1.6728 + if (gCaptureTouchList->Count() > 0 && touchEvent->touches.Length() > 1) { 1.6729 + gCaptureTouchList->Enumerate(&FindAnyTarget, &anyTarget); 1.6730 + } else { 1.6731 + gPreventMouseEvents = false; 1.6732 + } 1.6733 + 1.6734 + for (int32_t i = touchEvent->touches.Length(); i; ) { 1.6735 + --i; 1.6736 + dom::Touch* touch = touchEvent->touches[i]; 1.6737 + 1.6738 + int32_t id = touch->Identifier(); 1.6739 + if (!gCaptureTouchList->Get(id, nullptr)) { 1.6740 + // find the target for this touch 1.6741 + eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, 1.6742 + touch->mRefPoint, 1.6743 + frame); 1.6744 + nsIFrame* target = FindFrameTargetedByInputEvent(aEvent, 1.6745 + frame, 1.6746 + eventPoint, 1.6747 + flags); 1.6748 + if (target && !anyTarget) { 1.6749 + target->GetContentForEvent(aEvent, getter_AddRefs(anyTarget)); 1.6750 + while (anyTarget && !anyTarget->IsElement()) { 1.6751 + anyTarget = anyTarget->GetParent(); 1.6752 + } 1.6753 + touch->SetTarget(anyTarget); 1.6754 + } else { 1.6755 + nsIFrame* newTargetFrame = nullptr; 1.6756 + for (nsIFrame* f = target; f; 1.6757 + f = nsLayoutUtils::GetParentOrPlaceholderForCrossDoc(f)) { 1.6758 + if (f->PresContext()->Document() == anyTarget->OwnerDoc()) { 1.6759 + newTargetFrame = f; 1.6760 + break; 1.6761 + } 1.6762 + // We must be in a subdocument so jump directly to the root frame. 1.6763 + // GetParentOrPlaceholderForCrossDoc gets called immediately to 1.6764 + // jump up to the containing document. 1.6765 + f = f->PresContext()->GetPresShell()->GetRootFrame(); 1.6766 + } 1.6767 + 1.6768 + // if we couldn't find a target frame in the same document as 1.6769 + // anyTarget, remove the touch from the capture touch list, as 1.6770 + // well as the event->touches array. touchmove events that aren't 1.6771 + // in the captured touch list will be discarded 1.6772 + if (!newTargetFrame) { 1.6773 + touchEvent->touches.RemoveElementAt(i); 1.6774 + } else { 1.6775 + target = newTargetFrame; 1.6776 + nsCOMPtr<nsIContent> targetContent; 1.6777 + target->GetContentForEvent(aEvent, getter_AddRefs(targetContent)); 1.6778 + while (targetContent && !targetContent->IsElement()) { 1.6779 + targetContent = targetContent->GetParent(); 1.6780 + } 1.6781 + touch->SetTarget(targetContent); 1.6782 + } 1.6783 + } 1.6784 + if (target) { 1.6785 + frame = target; 1.6786 + } 1.6787 + } else { 1.6788 + // This touch is an old touch, we need to ensure that is not 1.6789 + // marked as changed and set its target correctly 1.6790 + touch->mChanged = false; 1.6791 + int32_t id = touch->Identifier(); 1.6792 + 1.6793 + nsRefPtr<dom::Touch> oldTouch = gCaptureTouchList->GetWeak(id); 1.6794 + if (oldTouch) { 1.6795 + touch->SetTarget(oldTouch->mTarget); 1.6796 + } 1.6797 + } 1.6798 + } 1.6799 + } else { 1.6800 + eventPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, frame); 1.6801 + } 1.6802 + if (mouseEvent && mouseEvent->eventStructType == NS_MOUSE_EVENT && 1.6803 + mouseEvent->ignoreRootScrollFrame) { 1.6804 + flags |= INPUT_IGNORE_ROOT_SCROLL_FRAME; 1.6805 + } 1.6806 + nsIFrame* target = 1.6807 + FindFrameTargetedByInputEvent(aEvent, frame, eventPoint, flags); 1.6808 + if (target) { 1.6809 + frame = target; 1.6810 + } 1.6811 + } 1.6812 + 1.6813 + // if a node is capturing the mouse, check if the event needs to be 1.6814 + // retargeted at the capturing content instead. This will be the case when 1.6815 + // capture retargeting is being used, no frame was found or the frame's 1.6816 + // content is not a descendant of the capturing content. 1.6817 + if (capturingContent && 1.6818 + (gCaptureInfo.mRetargetToElement || !frame->GetContent() || 1.6819 + !nsContentUtils::ContentIsCrossDocDescendantOf(frame->GetContent(), 1.6820 + capturingContent))) { 1.6821 + // A check was already done above to ensure that capturingContent is 1.6822 + // in this presshell. 1.6823 + NS_ASSERTION(capturingContent->GetCurrentDoc() == GetDocument(), 1.6824 + "Unexpected document"); 1.6825 + nsIFrame* capturingFrame = capturingContent->GetPrimaryFrame(); 1.6826 + if (capturingFrame) { 1.6827 + frame = capturingFrame; 1.6828 + } 1.6829 + } 1.6830 + 1.6831 + if (aEvent->eventStructType == NS_POINTER_EVENT && 1.6832 + aEvent->message != NS_POINTER_DOWN) { 1.6833 + if (WidgetPointerEvent* pointerEvent = aEvent->AsPointerEvent()) { 1.6834 + uint32_t pointerId = pointerEvent->pointerId; 1.6835 + nsIContent* pointerCapturingContent = GetPointerCapturingContent(pointerId); 1.6836 + 1.6837 + if (pointerCapturingContent) { 1.6838 + if (nsIFrame* capturingFrame = pointerCapturingContent->GetPrimaryFrame()) { 1.6839 + frame = capturingFrame; 1.6840 + } 1.6841 + 1.6842 + if (pointerEvent->message == NS_POINTER_UP || 1.6843 + pointerEvent->message == NS_POINTER_CANCEL) { 1.6844 + // Implicitly releasing capture for given pointer. 1.6845 + // LOST_POINTER_CAPTURE should be send after NS_POINTER_UP or NS_POINTER_CANCEL. 1.6846 + releasePointerCaptureCaller.SetTarget(pointerId, pointerCapturingContent); 1.6847 + } 1.6848 + } 1.6849 + } 1.6850 + } 1.6851 + 1.6852 + // Suppress mouse event if it's being targeted at an element inside 1.6853 + // a document which needs events suppressed 1.6854 + if (aEvent->eventStructType == NS_MOUSE_EVENT && 1.6855 + frame->PresContext()->Document()->EventHandlingSuppressed()) { 1.6856 + if (aEvent->message == NS_MOUSE_BUTTON_DOWN) { 1.6857 + mNoDelayedMouseEvents = true; 1.6858 + } else if (!mNoDelayedMouseEvents && aEvent->message == NS_MOUSE_BUTTON_UP) { 1.6859 + DelayedEvent* event = new DelayedMouseEvent(aEvent->AsMouseEvent()); 1.6860 + if (!mDelayedEvents.AppendElement(event)) { 1.6861 + delete event; 1.6862 + } 1.6863 + } 1.6864 + 1.6865 + return NS_OK; 1.6866 + } 1.6867 + 1.6868 + PresShell* shell = 1.6869 + static_cast<PresShell*>(frame->PresContext()->PresShell()); 1.6870 + switch (aEvent->message) { 1.6871 + case NS_TOUCH_MOVE: 1.6872 + case NS_TOUCH_CANCEL: 1.6873 + case NS_TOUCH_END: { 1.6874 + // get the correct shell to dispatch to 1.6875 + WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); 1.6876 + nsTArray< nsRefPtr<dom::Touch> >& touches = touchEvent->touches; 1.6877 + for (uint32_t i = 0; i < touches.Length(); ++i) { 1.6878 + dom::Touch* touch = touches[i]; 1.6879 + if (!touch) { 1.6880 + break; 1.6881 + } 1.6882 + 1.6883 + nsRefPtr<dom::Touch> oldTouch = 1.6884 + gCaptureTouchList->GetWeak(touch->Identifier()); 1.6885 + if (!oldTouch) { 1.6886 + break; 1.6887 + } 1.6888 + 1.6889 + nsCOMPtr<nsIContent> content = 1.6890 + do_QueryInterface(oldTouch->Target()); 1.6891 + if (!content) { 1.6892 + break; 1.6893 + } 1.6894 + 1.6895 + nsIFrame* contentFrame = content->GetPrimaryFrame(); 1.6896 + if (!contentFrame) { 1.6897 + break; 1.6898 + } 1.6899 + 1.6900 + shell = static_cast<PresShell*>( 1.6901 + contentFrame->PresContext()->PresShell()); 1.6902 + if (shell) { 1.6903 + break; 1.6904 + } 1.6905 + } 1.6906 + break; 1.6907 + } 1.6908 + } 1.6909 + 1.6910 + // Check if we have an active EventStateManager which isn't the 1.6911 + // EventStateManager of the current PresContext. 1.6912 + // If that is the case, and mouse is over some ancestor document, 1.6913 + // forward event handling to the active document. 1.6914 + // This way content can get mouse events even when 1.6915 + // mouse is over the chrome or outside the window. 1.6916 + // 1.6917 + // Note, currently for backwards compatibility we don't forward mouse events 1.6918 + // to the active document when mouse is over some subdocument. 1.6919 + EventStateManager* activeESM = 1.6920 + EventStateManager::GetActiveEventStateManager(); 1.6921 + if (activeESM && aEvent->HasMouseEventMessage() && 1.6922 + activeESM != shell->GetPresContext()->EventStateManager() && 1.6923 + static_cast<EventStateManager*>(activeESM)->GetPresContext()) { 1.6924 + nsIPresShell* activeShell = 1.6925 + static_cast<EventStateManager*>(activeESM)->GetPresContext()-> 1.6926 + GetPresShell(); 1.6927 + if (activeShell && 1.6928 + nsContentUtils::ContentIsCrossDocDescendantOf(activeShell->GetDocument(), 1.6929 + shell->GetDocument())) { 1.6930 + shell = static_cast<PresShell*>(activeShell); 1.6931 + frame = shell->GetRootFrame(); 1.6932 + } 1.6933 + } 1.6934 + 1.6935 + if (shell != this) { 1.6936 + // Handle the event in the correct shell. 1.6937 + // Prevent deletion until we're done with event handling (bug 336582). 1.6938 + nsCOMPtr<nsIPresShell> kungFuDeathGrip(shell); 1.6939 + // We pass the subshell's root frame as the frame to start from. This is 1.6940 + // the only correct alternative; if the event was captured then it 1.6941 + // must have been captured by us or some ancestor shell and we 1.6942 + // now ask the subshell to dispatch it normally. 1.6943 + return shell->HandlePositionedEvent(frame, aEvent, aEventStatus); 1.6944 + } 1.6945 + 1.6946 + return HandlePositionedEvent(frame, aEvent, aEventStatus); 1.6947 + } 1.6948 + 1.6949 + nsresult rv = NS_OK; 1.6950 + 1.6951 + if (frame) { 1.6952 + PushCurrentEventInfo(nullptr, nullptr); 1.6953 + 1.6954 + // key and IME related events go to the focused frame in this DOM window. 1.6955 + if (aEvent->IsTargetedAtFocusedContent()) { 1.6956 + mCurrentEventContent = nullptr; 1.6957 + 1.6958 + nsCOMPtr<nsPIDOMWindow> window = 1.6959 + do_QueryInterface(mDocument->GetWindow()); 1.6960 + nsCOMPtr<nsPIDOMWindow> focusedWindow; 1.6961 + nsCOMPtr<nsIContent> eventTarget = 1.6962 + nsFocusManager::GetFocusedDescendant(window, false, 1.6963 + getter_AddRefs(focusedWindow)); 1.6964 + 1.6965 + // otherwise, if there is no focused content or the focused content has 1.6966 + // no frame, just use the root content. This ensures that key events 1.6967 + // still get sent to the window properly if nothing is focused or if a 1.6968 + // frame goes away while it is focused. 1.6969 + if (!eventTarget || !eventTarget->GetPrimaryFrame()) { 1.6970 + nsCOMPtr<nsIDOMHTMLDocument> htmlDoc = do_QueryInterface(mDocument); 1.6971 + if (htmlDoc) { 1.6972 + nsCOMPtr<nsIDOMHTMLElement> body; 1.6973 + htmlDoc->GetBody(getter_AddRefs(body)); 1.6974 + eventTarget = do_QueryInterface(body); 1.6975 + if (!eventTarget) { 1.6976 + eventTarget = mDocument->GetRootElement(); 1.6977 + } 1.6978 + } else { 1.6979 + eventTarget = mDocument->GetRootElement(); 1.6980 + } 1.6981 + } 1.6982 + 1.6983 + if (aEvent->message == NS_KEY_DOWN) { 1.6984 + NS_IF_RELEASE(gKeyDownTarget); 1.6985 + NS_IF_ADDREF(gKeyDownTarget = eventTarget); 1.6986 + } 1.6987 + else if ((aEvent->message == NS_KEY_PRESS || aEvent->message == NS_KEY_UP) && 1.6988 + gKeyDownTarget) { 1.6989 + // If a different element is now focused for the keypress/keyup event 1.6990 + // than what was focused during the keydown event, check if the new 1.6991 + // focused element is not in a chrome document any more, and if so, 1.6992 + // retarget the event back at the keydown target. This prevents a 1.6993 + // content area from grabbing the focus from chrome in-between key 1.6994 + // events. 1.6995 + if (eventTarget && 1.6996 + nsContentUtils::IsChromeDoc(gKeyDownTarget->GetCurrentDoc()) != 1.6997 + nsContentUtils::IsChromeDoc(eventTarget->GetCurrentDoc())) { 1.6998 + eventTarget = gKeyDownTarget; 1.6999 + } 1.7000 + 1.7001 + if (aEvent->message == NS_KEY_UP) { 1.7002 + NS_RELEASE(gKeyDownTarget); 1.7003 + } 1.7004 + } 1.7005 + 1.7006 + mCurrentEventFrame = nullptr; 1.7007 + nsIDocument* targetDoc = eventTarget ? eventTarget->OwnerDoc() : nullptr; 1.7008 + if (targetDoc && targetDoc != mDocument) { 1.7009 + PopCurrentEventInfo(); 1.7010 + nsCOMPtr<nsIPresShell> shell = targetDoc->GetShell(); 1.7011 + if (shell) { 1.7012 + rv = static_cast<PresShell*>(shell.get())-> 1.7013 + HandleRetargetedEvent(aEvent, aEventStatus, eventTarget); 1.7014 + } 1.7015 + return rv; 1.7016 + } else { 1.7017 + mCurrentEventContent = eventTarget; 1.7018 + } 1.7019 + 1.7020 + if (!GetCurrentEventContent() || !GetCurrentEventFrame() || 1.7021 + InZombieDocument(mCurrentEventContent)) { 1.7022 + rv = RetargetEventToParent(aEvent, aEventStatus); 1.7023 + PopCurrentEventInfo(); 1.7024 + return rv; 1.7025 + } 1.7026 + } else { 1.7027 + mCurrentEventFrame = frame; 1.7028 + } 1.7029 + if (GetCurrentEventFrame()) { 1.7030 + rv = HandleEventInternal(aEvent, aEventStatus); 1.7031 + } 1.7032 + 1.7033 +#ifdef DEBUG 1.7034 + ShowEventTargetDebug(); 1.7035 +#endif 1.7036 + PopCurrentEventInfo(); 1.7037 + } else { 1.7038 + // Activation events need to be dispatched even if no frame was found, since 1.7039 + // we don't want the focus to be out of sync. 1.7040 + 1.7041 + if (!NS_EVENT_NEEDS_FRAME(aEvent)) { 1.7042 + mCurrentEventFrame = nullptr; 1.7043 + return HandleEventInternal(aEvent, aEventStatus); 1.7044 + } 1.7045 + else if (aEvent->HasKeyEventMessage()) { 1.7046 + // Keypress events in new blank tabs should not be completely thrown away. 1.7047 + // Retarget them -- the parent chrome shell might make use of them. 1.7048 + return RetargetEventToParent(aEvent, aEventStatus); 1.7049 + } 1.7050 + } 1.7051 + 1.7052 + return rv; 1.7053 +} 1.7054 + 1.7055 +#ifdef ANDROID 1.7056 +nsIDocument* 1.7057 +PresShell::GetTouchEventTargetDocument() 1.7058 +{ 1.7059 + nsPresContext* context = GetPresContext(); 1.7060 + if (!context || !context->IsRoot()) { 1.7061 + return nullptr; 1.7062 + } 1.7063 + 1.7064 + nsCOMPtr<nsIDocShellTreeItem> shellAsTreeItem = context->GetDocShell(); 1.7065 + if (!shellAsTreeItem) { 1.7066 + return nullptr; 1.7067 + } 1.7068 + 1.7069 + nsCOMPtr<nsIDocShellTreeOwner> owner; 1.7070 + shellAsTreeItem->GetTreeOwner(getter_AddRefs(owner)); 1.7071 + if (!owner) { 1.7072 + return nullptr; 1.7073 + } 1.7074 + 1.7075 + // now get the primary content shell (active tab) 1.7076 + nsCOMPtr<nsIDocShellTreeItem> item; 1.7077 + owner->GetPrimaryContentShell(getter_AddRefs(item)); 1.7078 + nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(item); 1.7079 + nsCOMPtr<nsIDocument> result = do_GetInterface(childDocShell); 1.7080 + return result; 1.7081 +} 1.7082 +#endif 1.7083 + 1.7084 +#ifdef DEBUG 1.7085 +void 1.7086 +PresShell::ShowEventTargetDebug() 1.7087 +{ 1.7088 + if (nsFrame::GetShowEventTargetFrameBorder() && 1.7089 + GetCurrentEventFrame()) { 1.7090 + if (mDrawEventTargetFrame) { 1.7091 + mDrawEventTargetFrame->InvalidateFrame(); 1.7092 + } 1.7093 + 1.7094 + mDrawEventTargetFrame = mCurrentEventFrame; 1.7095 + mDrawEventTargetFrame->InvalidateFrame(); 1.7096 + } 1.7097 +} 1.7098 +#endif 1.7099 + 1.7100 +nsresult 1.7101 +PresShell::HandlePositionedEvent(nsIFrame* aTargetFrame, 1.7102 + WidgetGUIEvent* aEvent, 1.7103 + nsEventStatus* aEventStatus) 1.7104 +{ 1.7105 + nsresult rv = NS_OK; 1.7106 + 1.7107 + PushCurrentEventInfo(nullptr, nullptr); 1.7108 + 1.7109 + mCurrentEventFrame = aTargetFrame; 1.7110 + 1.7111 + if (mCurrentEventFrame) { 1.7112 + nsCOMPtr<nsIContent> targetElement; 1.7113 + mCurrentEventFrame->GetContentForEvent(aEvent, 1.7114 + getter_AddRefs(targetElement)); 1.7115 + 1.7116 + // If there is no content for this frame, target it anyway. Some 1.7117 + // frames can be targeted but do not have content, particularly 1.7118 + // windows with scrolling off. 1.7119 + if (targetElement) { 1.7120 + // Bug 103055, bug 185889: mouse events apply to *elements*, not all 1.7121 + // nodes. Thus we get the nearest element parent here. 1.7122 + // XXX we leave the frame the same even if we find an element 1.7123 + // parent, so that the text frame will receive the event (selection 1.7124 + // and friends are the ones who care about that anyway) 1.7125 + // 1.7126 + // We use weak pointers because during this tight loop, the node 1.7127 + // will *not* go away. And this happens on every mousemove. 1.7128 + while (targetElement && !targetElement->IsElement()) { 1.7129 + targetElement = targetElement->GetParent(); 1.7130 + } 1.7131 + 1.7132 + // If we found an element, target it. Otherwise, target *nothing*. 1.7133 + if (!targetElement) { 1.7134 + mCurrentEventContent = nullptr; 1.7135 + mCurrentEventFrame = nullptr; 1.7136 + } else if (targetElement != mCurrentEventContent) { 1.7137 + mCurrentEventContent = targetElement; 1.7138 + } 1.7139 + } 1.7140 + } 1.7141 + 1.7142 + if (GetCurrentEventFrame()) { 1.7143 + rv = HandleEventInternal(aEvent, aEventStatus); 1.7144 + } 1.7145 + 1.7146 +#ifdef DEBUG 1.7147 + ShowEventTargetDebug(); 1.7148 +#endif 1.7149 + PopCurrentEventInfo(); 1.7150 + return rv; 1.7151 +} 1.7152 + 1.7153 +nsresult 1.7154 +PresShell::HandleEventWithTarget(WidgetEvent* aEvent, nsIFrame* aFrame, 1.7155 + nsIContent* aContent, nsEventStatus* aStatus) 1.7156 +{ 1.7157 +#if DEBUG 1.7158 + MOZ_ASSERT(!aFrame || aFrame->PresContext()->GetPresShell() == this, 1.7159 + "wrong shell"); 1.7160 + if (aContent) { 1.7161 + nsIDocument* doc = aContent->GetCurrentDoc(); 1.7162 + NS_ASSERTION(doc, "event for content that isn't in a document"); 1.7163 + NS_ASSERTION(!doc || doc->GetShell() == this, "wrong shell"); 1.7164 + } 1.7165 +#endif 1.7166 + NS_ENSURE_STATE(!aContent || aContent->GetCurrentDoc() == mDocument); 1.7167 + 1.7168 + PushCurrentEventInfo(aFrame, aContent); 1.7169 + nsresult rv = HandleEventInternal(aEvent, aStatus); 1.7170 + PopCurrentEventInfo(); 1.7171 + return rv; 1.7172 +} 1.7173 + 1.7174 +nsresult 1.7175 +PresShell::HandleEventInternal(WidgetEvent* aEvent, nsEventStatus* aStatus) 1.7176 +{ 1.7177 + nsRefPtr<EventStateManager> manager = mPresContext->EventStateManager(); 1.7178 + nsresult rv = NS_OK; 1.7179 + 1.7180 + if (!NS_EVENT_NEEDS_FRAME(aEvent) || GetCurrentEventFrame()) { 1.7181 + bool touchIsNew = false; 1.7182 + bool isHandlingUserInput = false; 1.7183 + 1.7184 + // XXX How about IME events and input events for plugins? 1.7185 + if (aEvent->mFlags.mIsTrusted) { 1.7186 + switch (aEvent->message) { 1.7187 + case NS_KEY_PRESS: 1.7188 + case NS_KEY_DOWN: 1.7189 + case NS_KEY_UP: { 1.7190 + nsIDocument* doc = GetCurrentEventContent() ? 1.7191 + mCurrentEventContent->OwnerDoc() : nullptr; 1.7192 + nsIDocument* fullscreenAncestor = nullptr; 1.7193 + if (aEvent->AsKeyboardEvent()->keyCode == NS_VK_ESCAPE) { 1.7194 + if ((fullscreenAncestor = nsContentUtils::GetFullscreenAncestor(doc))) { 1.7195 + // Prevent default action on ESC key press when exiting 1.7196 + // DOM fullscreen mode. This prevents the browser ESC key 1.7197 + // handler from stopping all loads in the document, which 1.7198 + // would cause <video> loads to stop. 1.7199 + aEvent->mFlags.mDefaultPrevented = true; 1.7200 + aEvent->mFlags.mOnlyChromeDispatch = true; 1.7201 + 1.7202 + if (aEvent->message == NS_KEY_UP) { 1.7203 + // ESC key released while in DOM fullscreen mode. 1.7204 + // If fullscreen is running in content-only mode, exit the target 1.7205 + // doctree branch from fullscreen, otherwise fully exit all 1.7206 + // browser windows and documents from fullscreen mode. 1.7207 + // Note: in the content-only fullscreen case, we pass the 1.7208 + // fullscreenAncestor since |doc| may not actually be fullscreen 1.7209 + // here, and ExitFullscreen() has no affect when passed a 1.7210 + // non-fullscreen document. 1.7211 + nsIDocument::ExitFullscreen( 1.7212 + nsContentUtils::IsFullscreenApiContentOnly() ? fullscreenAncestor : nullptr, 1.7213 + /* async */ true); 1.7214 + } 1.7215 + } 1.7216 + nsCOMPtr<nsIDocument> pointerLockedDoc = 1.7217 + do_QueryReferent(EventStateManager::sPointerLockedDoc); 1.7218 + if (pointerLockedDoc) { 1.7219 + aEvent->mFlags.mDefaultPrevented = true; 1.7220 + aEvent->mFlags.mOnlyChromeDispatch = true; 1.7221 + if (aEvent->message == NS_KEY_UP) { 1.7222 + nsIDocument::UnlockPointer(); 1.7223 + } 1.7224 + } 1.7225 + } 1.7226 + // Else not full-screen mode or key code is unrestricted, fall 1.7227 + // through to normal handling. 1.7228 + } 1.7229 + case NS_MOUSE_BUTTON_DOWN: 1.7230 + case NS_MOUSE_BUTTON_UP: 1.7231 + isHandlingUserInput = true; 1.7232 + break; 1.7233 + case NS_TOUCH_START: { 1.7234 + WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); 1.7235 + // if there is only one touch in this touchstart event, assume that it is 1.7236 + // the start of a new touch session and evict any old touches in the 1.7237 + // queue 1.7238 + if (touchEvent->touches.Length() == 1) { 1.7239 + nsTArray< nsRefPtr<dom::Touch> > touches; 1.7240 + gCaptureTouchList->Enumerate(&AppendToTouchList, (void *)&touches); 1.7241 + for (uint32_t i = 0; i < touches.Length(); ++i) { 1.7242 + EvictTouchPoint(touches[i]); 1.7243 + } 1.7244 + } 1.7245 + // Add any new touches to the queue 1.7246 + for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) { 1.7247 + dom::Touch* touch = touchEvent->touches[i]; 1.7248 + int32_t id = touch->Identifier(); 1.7249 + if (!gCaptureTouchList->Get(id, nullptr)) { 1.7250 + // If it is not already in the queue, it is a new touch 1.7251 + touch->mChanged = true; 1.7252 + } 1.7253 + touch->mMessage = aEvent->message; 1.7254 + gCaptureTouchList->Put(id, touch); 1.7255 + } 1.7256 + break; 1.7257 + } 1.7258 + case NS_TOUCH_CANCEL: 1.7259 + case NS_TOUCH_END: { 1.7260 + // Remove the changed touches 1.7261 + // need to make sure we only remove touches that are ending here 1.7262 + WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); 1.7263 + nsTArray< nsRefPtr<dom::Touch> >& touches = touchEvent->touches; 1.7264 + for (uint32_t i = 0; i < touches.Length(); ++i) { 1.7265 + dom::Touch* touch = touches[i]; 1.7266 + if (!touch) { 1.7267 + continue; 1.7268 + } 1.7269 + touch->mMessage = aEvent->message; 1.7270 + touch->mChanged = true; 1.7271 + 1.7272 + int32_t id = touch->Identifier(); 1.7273 + nsRefPtr<dom::Touch> oldTouch = gCaptureTouchList->GetWeak(id); 1.7274 + if (!oldTouch) { 1.7275 + continue; 1.7276 + } 1.7277 + nsCOMPtr<EventTarget> targetPtr = oldTouch->mTarget; 1.7278 + 1.7279 + mCurrentEventContent = do_QueryInterface(targetPtr); 1.7280 + touch->SetTarget(targetPtr); 1.7281 + gCaptureTouchList->Remove(id); 1.7282 + } 1.7283 + // add any touches left in the touch list, but ensure changed=false 1.7284 + gCaptureTouchList->Enumerate(&AppendToTouchList, (void *)&touches); 1.7285 + break; 1.7286 + } 1.7287 + case NS_TOUCH_MOVE: { 1.7288 + // Check for touches that changed. Mark them add to queue 1.7289 + WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); 1.7290 + nsTArray< nsRefPtr<dom::Touch> >& touches = touchEvent->touches; 1.7291 + bool haveChanged = false; 1.7292 + for (int32_t i = touches.Length(); i; ) { 1.7293 + --i; 1.7294 + dom::Touch* touch = touches[i]; 1.7295 + if (!touch) { 1.7296 + continue; 1.7297 + } 1.7298 + int32_t id = touch->Identifier(); 1.7299 + touch->mMessage = aEvent->message; 1.7300 + 1.7301 + nsRefPtr<dom::Touch> oldTouch = gCaptureTouchList->GetWeak(id); 1.7302 + if (!oldTouch) { 1.7303 + touches.RemoveElementAt(i); 1.7304 + continue; 1.7305 + } 1.7306 + if (!touch->Equals(oldTouch)) { 1.7307 + touch->mChanged = true; 1.7308 + haveChanged = true; 1.7309 + } 1.7310 + 1.7311 + nsCOMPtr<dom::EventTarget> targetPtr = oldTouch->mTarget; 1.7312 + if (!targetPtr) { 1.7313 + touches.RemoveElementAt(i); 1.7314 + continue; 1.7315 + } 1.7316 + touch->SetTarget(targetPtr); 1.7317 + 1.7318 + gCaptureTouchList->Put(id, touch); 1.7319 + // if we're moving from touchstart to touchmove for this touch 1.7320 + // we allow preventDefault to prevent mouse events 1.7321 + if (oldTouch->mMessage != touch->mMessage) { 1.7322 + touchIsNew = true; 1.7323 + } 1.7324 + } 1.7325 + // is nothing has changed, we should just return 1.7326 + if (!haveChanged) { 1.7327 + if (gPreventMouseEvents) { 1.7328 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.7329 + } 1.7330 + return NS_OK; 1.7331 + } 1.7332 + break; 1.7333 + } 1.7334 + case NS_DRAGDROP_DROP: 1.7335 + nsCOMPtr<nsIDragSession> session = nsContentUtils::GetDragSession(); 1.7336 + if (session) { 1.7337 + bool onlyChromeDrop = false; 1.7338 + session->GetOnlyChromeDrop(&onlyChromeDrop); 1.7339 + if (onlyChromeDrop) { 1.7340 + aEvent->mFlags.mOnlyChromeDispatch = true; 1.7341 + } 1.7342 + } 1.7343 + break; 1.7344 + } 1.7345 + } 1.7346 + 1.7347 + if (aEvent->message == NS_CONTEXTMENU) { 1.7348 + WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent(); 1.7349 + if (mouseEvent->context == WidgetMouseEvent::eContextMenuKey && 1.7350 + !AdjustContextMenuKeyEvent(mouseEvent)) { 1.7351 + return NS_OK; 1.7352 + } 1.7353 + if (mouseEvent->IsShift()) { 1.7354 + aEvent->mFlags.mOnlyChromeDispatch = true; 1.7355 + aEvent->mFlags.mRetargetToNonNativeAnonymous = true; 1.7356 + } 1.7357 + } 1.7358 + 1.7359 + AutoHandlingUserInputStatePusher userInpStatePusher(isHandlingUserInput, 1.7360 + aEvent, mDocument); 1.7361 + 1.7362 + if (aEvent->mFlags.mIsTrusted && aEvent->message == NS_MOUSE_MOVE) { 1.7363 + nsIPresShell::AllowMouseCapture( 1.7364 + EventStateManager::GetActiveEventStateManager() == manager); 1.7365 + } 1.7366 + 1.7367 + nsAutoPopupStatePusher popupStatePusher( 1.7368 + Event::GetEventPopupControlState(aEvent)); 1.7369 + 1.7370 + // FIXME. If the event was reused, we need to clear the old target, 1.7371 + // bug 329430 1.7372 + aEvent->target = nullptr; 1.7373 + 1.7374 + // 1. Give event to event manager for pre event state changes and 1.7375 + // generation of synthetic events. 1.7376 + rv = manager->PreHandleEvent(mPresContext, aEvent, mCurrentEventFrame, aStatus); 1.7377 + 1.7378 + // 2. Give event to the DOM for third party and JS use. 1.7379 + if (NS_SUCCEEDED(rv)) { 1.7380 + bool wasHandlingKeyBoardEvent = 1.7381 + nsContentUtils::IsHandlingKeyBoardEvent(); 1.7382 + if (aEvent->eventStructType == NS_KEY_EVENT) { 1.7383 + nsContentUtils::SetIsHandlingKeyBoardEvent(true); 1.7384 + } 1.7385 + if (aEvent->IsAllowedToDispatchDOMEvent()) { 1.7386 + nsPresShellEventCB eventCB(this); 1.7387 + if (aEvent->eventStructType == NS_TOUCH_EVENT) { 1.7388 + DispatchTouchEvent(aEvent, aStatus, &eventCB, touchIsNew); 1.7389 + } else { 1.7390 + nsCOMPtr<nsINode> eventTarget = mCurrentEventContent.get(); 1.7391 + nsPresShellEventCB* eventCBPtr = &eventCB; 1.7392 + if (!eventTarget) { 1.7393 + nsCOMPtr<nsIContent> targetContent; 1.7394 + if (mCurrentEventFrame) { 1.7395 + rv = mCurrentEventFrame-> 1.7396 + GetContentForEvent(aEvent, getter_AddRefs(targetContent)); 1.7397 + } 1.7398 + if (NS_SUCCEEDED(rv) && targetContent) { 1.7399 + eventTarget = do_QueryInterface(targetContent); 1.7400 + } else if (mDocument) { 1.7401 + eventTarget = do_QueryInterface(mDocument); 1.7402 + // If we don't have any content, the callback wouldn't probably 1.7403 + // do nothing. 1.7404 + eventCBPtr = nullptr; 1.7405 + } 1.7406 + } 1.7407 + if (eventTarget) { 1.7408 + if (aEvent->eventStructType == NS_COMPOSITION_EVENT || 1.7409 + aEvent->eventStructType == NS_TEXT_EVENT) { 1.7410 + IMEStateManager::DispatchCompositionEvent(eventTarget, 1.7411 + mPresContext, aEvent, aStatus, eventCBPtr); 1.7412 + } else { 1.7413 + EventDispatcher::Dispatch(eventTarget, mPresContext, 1.7414 + aEvent, nullptr, aStatus, eventCBPtr); 1.7415 + } 1.7416 + } 1.7417 + } 1.7418 + } 1.7419 + 1.7420 + nsContentUtils::SetIsHandlingKeyBoardEvent(wasHandlingKeyBoardEvent); 1.7421 + 1.7422 + // 3. Give event to event manager for post event state changes and 1.7423 + // generation of synthetic events. 1.7424 + if (!mIsDestroying && NS_SUCCEEDED(rv)) { 1.7425 + rv = manager->PostHandleEvent(mPresContext, aEvent, 1.7426 + GetCurrentEventFrame(), aStatus); 1.7427 + } 1.7428 + } 1.7429 + 1.7430 + if (aEvent->message == NS_MOUSE_BUTTON_UP) { 1.7431 + // reset the capturing content now that the mouse button is up 1.7432 + SetCapturingContent(nullptr, 0); 1.7433 + } else if (aEvent->message == NS_MOUSE_MOVE) { 1.7434 + nsIPresShell::AllowMouseCapture(false); 1.7435 + } 1.7436 + } 1.7437 + return rv; 1.7438 +} 1.7439 + 1.7440 +void 1.7441 +nsIPresShell::DispatchGotOrLostPointerCaptureEvent(bool aIsGotCapture, 1.7442 + uint32_t aPointerId, 1.7443 + nsIContent* aCaptureTarget) 1.7444 +{ 1.7445 + PointerEventInit init; 1.7446 + init.mPointerId = aPointerId; 1.7447 + init.mBubbles = true; 1.7448 + nsRefPtr<mozilla::dom::PointerEvent> event; 1.7449 + event = PointerEvent::Constructor(aCaptureTarget, 1.7450 + aIsGotCapture 1.7451 + ? NS_LITERAL_STRING("gotpointercapture") 1.7452 + : NS_LITERAL_STRING("lostpointercapture"), 1.7453 + init); 1.7454 + if (event) { 1.7455 + bool dummy; 1.7456 + aCaptureTarget->DispatchEvent(event->InternalDOMEvent(), &dummy); 1.7457 + } 1.7458 +} 1.7459 + 1.7460 +void 1.7461 +PresShell::DispatchTouchEvent(WidgetEvent* aEvent, 1.7462 + nsEventStatus* aStatus, 1.7463 + nsPresShellEventCB* aEventCB, 1.7464 + bool aTouchIsNew) 1.7465 +{ 1.7466 + // calling preventDefault on touchstart or the first touchmove for a 1.7467 + // point prevents mouse events 1.7468 + bool canPrevent = aEvent->message == NS_TOUCH_START || 1.7469 + (aEvent->message == NS_TOUCH_MOVE && aTouchIsNew); 1.7470 + bool preventDefault = false; 1.7471 + nsEventStatus tmpStatus = nsEventStatus_eIgnore; 1.7472 + WidgetTouchEvent* touchEvent = aEvent->AsTouchEvent(); 1.7473 + 1.7474 + // loop over all touches and dispatch events on any that have changed 1.7475 + for (uint32_t i = 0; i < touchEvent->touches.Length(); ++i) { 1.7476 + dom::Touch* touch = touchEvent->touches[i]; 1.7477 + if (!touch || !touch->mChanged) { 1.7478 + continue; 1.7479 + } 1.7480 + 1.7481 + nsCOMPtr<EventTarget> targetPtr = touch->mTarget; 1.7482 + nsCOMPtr<nsIContent> content = do_QueryInterface(targetPtr); 1.7483 + if (!content) { 1.7484 + continue; 1.7485 + } 1.7486 + 1.7487 + nsIDocument* doc = content->OwnerDoc(); 1.7488 + nsIContent* capturingContent = GetCapturingContent(); 1.7489 + if (capturingContent) { 1.7490 + if (capturingContent->OwnerDoc() != doc) { 1.7491 + // Wrong document, don't dispatch anything. 1.7492 + continue; 1.7493 + } 1.7494 + content = capturingContent; 1.7495 + } 1.7496 + // copy the event 1.7497 + WidgetTouchEvent newEvent(touchEvent->mFlags.mIsTrusted, 1.7498 + touchEvent->message, touchEvent->widget); 1.7499 + newEvent.AssignTouchEventData(*touchEvent, false); 1.7500 + newEvent.target = targetPtr; 1.7501 + 1.7502 + nsRefPtr<PresShell> contentPresShell; 1.7503 + if (doc == mDocument) { 1.7504 + contentPresShell = static_cast<PresShell*>(doc->GetShell()); 1.7505 + if (contentPresShell) { 1.7506 + //XXXsmaug huge hack. Pushing possibly capturing content, 1.7507 + // even though event target is something else. 1.7508 + contentPresShell->PushCurrentEventInfo( 1.7509 + content->GetPrimaryFrame(), content); 1.7510 + } 1.7511 + } 1.7512 + 1.7513 + nsIPresShell *presShell = doc->GetShell(); 1.7514 + if (!presShell) { 1.7515 + continue; 1.7516 + } 1.7517 + 1.7518 + nsPresContext *context = presShell->GetPresContext(); 1.7519 + 1.7520 + tmpStatus = nsEventStatus_eIgnore; 1.7521 + EventDispatcher::Dispatch(targetPtr, context, 1.7522 + &newEvent, nullptr, &tmpStatus, aEventCB); 1.7523 + if (nsEventStatus_eConsumeNoDefault == tmpStatus || 1.7524 + newEvent.mFlags.mMultipleActionsPrevented) { 1.7525 + preventDefault = true; 1.7526 + } 1.7527 + 1.7528 + if (newEvent.mFlags.mMultipleActionsPrevented) { 1.7529 + touchEvent->mFlags.mMultipleActionsPrevented = true; 1.7530 + } 1.7531 + 1.7532 + if (contentPresShell) { 1.7533 + contentPresShell->PopCurrentEventInfo(); 1.7534 + } 1.7535 + } 1.7536 + 1.7537 + // if preventDefault was called on any of the events dispatched 1.7538 + // and this is touchstart, or the first touchmove, widget should consume 1.7539 + // other events that would be associated with this touch session 1.7540 + if (preventDefault && canPrevent) { 1.7541 + gPreventMouseEvents = true; 1.7542 + } 1.7543 + 1.7544 + if (gPreventMouseEvents) { 1.7545 + *aStatus = nsEventStatus_eConsumeNoDefault; 1.7546 + } else { 1.7547 + *aStatus = nsEventStatus_eIgnore; 1.7548 + } 1.7549 +} 1.7550 + 1.7551 +// Dispatch event to content only (NOT full processing) 1.7552 +// See also HandleEventWithTarget which does full event processing. 1.7553 +nsresult 1.7554 +PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent, 1.7555 + WidgetEvent* aEvent, 1.7556 + nsEventStatus* aStatus) 1.7557 +{ 1.7558 + nsresult rv = NS_OK; 1.7559 + 1.7560 + PushCurrentEventInfo(nullptr, aTargetContent); 1.7561 + 1.7562 + // Bug 41013: Check if the event should be dispatched to content. 1.7563 + // It's possible that we are in the middle of destroying the window 1.7564 + // and the js context is out of date. This check detects the case 1.7565 + // that caused a crash in bug 41013, but there may be a better way 1.7566 + // to handle this situation! 1.7567 + nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak(); 1.7568 + if (container) { 1.7569 + 1.7570 + // Dispatch event to content 1.7571 + rv = EventDispatcher::Dispatch(aTargetContent, mPresContext, aEvent, 1.7572 + nullptr, aStatus); 1.7573 + } 1.7574 + 1.7575 + PopCurrentEventInfo(); 1.7576 + return rv; 1.7577 +} 1.7578 + 1.7579 +// See the method above. 1.7580 +nsresult 1.7581 +PresShell::HandleDOMEventWithTarget(nsIContent* aTargetContent, 1.7582 + nsIDOMEvent* aEvent, 1.7583 + nsEventStatus* aStatus) 1.7584 +{ 1.7585 + nsresult rv = NS_OK; 1.7586 + 1.7587 + PushCurrentEventInfo(nullptr, aTargetContent); 1.7588 + nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak(); 1.7589 + if (container) { 1.7590 + rv = EventDispatcher::DispatchDOMEvent(aTargetContent, nullptr, aEvent, 1.7591 + mPresContext, aStatus); 1.7592 + } 1.7593 + 1.7594 + PopCurrentEventInfo(); 1.7595 + return rv; 1.7596 +} 1.7597 + 1.7598 +bool 1.7599 +PresShell::AdjustContextMenuKeyEvent(WidgetMouseEvent* aEvent) 1.7600 +{ 1.7601 +#ifdef MOZ_XUL 1.7602 + // if a menu is open, open the context menu relative to the active item on the menu. 1.7603 + nsXULPopupManager* pm = nsXULPopupManager::GetInstance(); 1.7604 + if (pm) { 1.7605 + nsIFrame* popupFrame = pm->GetTopPopup(ePopupTypeMenu); 1.7606 + if (popupFrame) { 1.7607 + nsIFrame* itemFrame = 1.7608 + (static_cast<nsMenuPopupFrame *>(popupFrame))->GetCurrentMenuItem(); 1.7609 + if (!itemFrame) 1.7610 + itemFrame = popupFrame; 1.7611 + 1.7612 + nsCOMPtr<nsIWidget> widget = popupFrame->GetNearestWidget(); 1.7613 + aEvent->widget = widget; 1.7614 + nsIntPoint widgetPoint = widget->WidgetToScreenOffset(); 1.7615 + aEvent->refPoint = LayoutDeviceIntPoint::FromUntyped( 1.7616 + itemFrame->GetScreenRect().BottomLeft() - widgetPoint); 1.7617 + 1.7618 + mCurrentEventContent = itemFrame->GetContent(); 1.7619 + mCurrentEventFrame = itemFrame; 1.7620 + 1.7621 + return true; 1.7622 + } 1.7623 + } 1.7624 +#endif 1.7625 + 1.7626 + // If we're here because of the key-equiv for showing context menus, we 1.7627 + // have to twiddle with the NS event to make sure the context menu comes 1.7628 + // up in the upper left of the relevant content area before we create 1.7629 + // the DOM event. Since we never call InitMouseEvent() on the event, 1.7630 + // the client X/Y will be 0,0. We can make use of that if the widget is null. 1.7631 + // Use the root view manager's widget since it's most likely to have one, 1.7632 + // and the coordinates returned by GetCurrentItemAndPositionForElement 1.7633 + // are relative to the widget of the root of the root view manager. 1.7634 + nsRootPresContext* rootPC = mPresContext->GetRootPresContext(); 1.7635 + aEvent->refPoint.x = 0; 1.7636 + aEvent->refPoint.y = 0; 1.7637 + if (rootPC) { 1.7638 + rootPC->PresShell()->GetViewManager()-> 1.7639 + GetRootWidget(getter_AddRefs(aEvent->widget)); 1.7640 + 1.7641 + if (aEvent->widget) { 1.7642 + // default the refpoint to the topleft of our document 1.7643 + nsPoint offset(0, 0); 1.7644 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.7645 + if (rootFrame) { 1.7646 + nsView* view = rootFrame->GetClosestView(&offset); 1.7647 + offset += view->GetOffsetToWidget(aEvent->widget); 1.7648 + aEvent->refPoint = 1.7649 + LayoutDeviceIntPoint::FromAppUnitsToNearest(offset, mPresContext->AppUnitsPerDevPixel()); 1.7650 + } 1.7651 + } 1.7652 + } else { 1.7653 + aEvent->widget = nullptr; 1.7654 + } 1.7655 + 1.7656 + // see if we should use the caret position for the popup 1.7657 + nsIntPoint caretPoint; 1.7658 + // Beware! This may flush notifications via synchronous 1.7659 + // ScrollSelectionIntoView. 1.7660 + if (PrepareToUseCaretPosition(aEvent->widget, caretPoint)) { 1.7661 + // caret position is good 1.7662 + aEvent->refPoint = LayoutDeviceIntPoint::FromUntyped(caretPoint); 1.7663 + return true; 1.7664 + } 1.7665 + 1.7666 + // If we're here because of the key-equiv for showing context menus, we 1.7667 + // have to reset the event target to the currently focused element. Get it 1.7668 + // from the focus controller. 1.7669 + nsCOMPtr<nsIDOMElement> currentFocus; 1.7670 + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); 1.7671 + if (fm) 1.7672 + fm->GetFocusedElement(getter_AddRefs(currentFocus)); 1.7673 + 1.7674 + // Reset event coordinates relative to focused frame in view 1.7675 + if (currentFocus) { 1.7676 + nsCOMPtr<nsIContent> currentPointElement; 1.7677 + GetCurrentItemAndPositionForElement(currentFocus, 1.7678 + getter_AddRefs(currentPointElement), 1.7679 + aEvent->refPoint, 1.7680 + aEvent->widget); 1.7681 + if (currentPointElement) { 1.7682 + mCurrentEventContent = currentPointElement; 1.7683 + mCurrentEventFrame = nullptr; 1.7684 + GetCurrentEventFrame(); 1.7685 + } 1.7686 + } 1.7687 + 1.7688 + return true; 1.7689 +} 1.7690 + 1.7691 +// PresShell::PrepareToUseCaretPosition 1.7692 +// 1.7693 +// This checks to see if we should use the caret position for popup context 1.7694 +// menus. Returns true if the caret position should be used, and the 1.7695 +// coordinates of that position is returned in aTargetPt. This function 1.7696 +// will also scroll the window as needed to make the caret visible. 1.7697 +// 1.7698 +// The event widget should be the widget that generated the event, and 1.7699 +// whose coordinate system the resulting event's refPoint should be 1.7700 +// relative to. The returned point is in device pixels realtive to the 1.7701 +// widget passed in. 1.7702 +bool 1.7703 +PresShell::PrepareToUseCaretPosition(nsIWidget* aEventWidget, nsIntPoint& aTargetPt) 1.7704 +{ 1.7705 + nsresult rv; 1.7706 + 1.7707 + // check caret visibility 1.7708 + nsRefPtr<nsCaret> caret = GetCaret(); 1.7709 + NS_ENSURE_TRUE(caret, false); 1.7710 + 1.7711 + bool caretVisible = false; 1.7712 + rv = caret->GetCaretVisible(&caretVisible); 1.7713 + if (NS_FAILED(rv) || ! caretVisible) 1.7714 + return false; 1.7715 + 1.7716 + // caret selection, this is a temporary weak reference, so no refcounting is 1.7717 + // needed 1.7718 + nsISelection* domSelection = caret->GetCaretDOMSelection(); 1.7719 + NS_ENSURE_TRUE(domSelection, false); 1.7720 + 1.7721 + // since the match could be an anonymous textnode inside a 1.7722 + // <textarea> or text <input>, we need to get the outer frame 1.7723 + // note: frames are not refcounted 1.7724 + nsIFrame* frame = nullptr; // may be nullptr 1.7725 + nsCOMPtr<nsIDOMNode> node; 1.7726 + rv = domSelection->GetFocusNode(getter_AddRefs(node)); 1.7727 + NS_ENSURE_SUCCESS(rv, false); 1.7728 + NS_ENSURE_TRUE(node, false); 1.7729 + nsCOMPtr<nsIContent> content(do_QueryInterface(node)); 1.7730 + if (content) { 1.7731 + nsIContent* nonNative = content->FindFirstNonChromeOnlyAccessContent(); 1.7732 + content = nonNative; 1.7733 + } 1.7734 + 1.7735 + if (content) { 1.7736 + // It seems like ScrollSelectionIntoView should be enough, but it's 1.7737 + // not. The problem is that scrolling the selection into view when it is 1.7738 + // below the current viewport will align the top line of the frame exactly 1.7739 + // with the bottom of the window. This is fine, BUT, the popup event causes 1.7740 + // the control to be re-focused which does this exact call to 1.7741 + // ScrollContentIntoView, which has a one-pixel disagreement of whether the 1.7742 + // frame is actually in view. The result is that the frame is aligned with 1.7743 + // the top of the window, but the menu is still at the bottom. 1.7744 + // 1.7745 + // Doing this call first forces the frame to be in view, eliminating the 1.7746 + // problem. The only difference in the result is that if your cursor is in 1.7747 + // an edit box below the current view, you'll get the edit box aligned with 1.7748 + // the top of the window. This is arguably better behavior anyway. 1.7749 + rv = ScrollContentIntoView(content, 1.7750 + nsIPresShell::ScrollAxis( 1.7751 + nsIPresShell::SCROLL_MINIMUM, 1.7752 + nsIPresShell::SCROLL_IF_NOT_VISIBLE), 1.7753 + nsIPresShell::ScrollAxis( 1.7754 + nsIPresShell::SCROLL_MINIMUM, 1.7755 + nsIPresShell::SCROLL_IF_NOT_VISIBLE), 1.7756 + nsIPresShell::SCROLL_OVERFLOW_HIDDEN); 1.7757 + NS_ENSURE_SUCCESS(rv, false); 1.7758 + frame = content->GetPrimaryFrame(); 1.7759 + NS_WARN_IF_FALSE(frame, "No frame for focused content?"); 1.7760 + } 1.7761 + 1.7762 + // Actually scroll the selection (ie caret) into view. Note that this must 1.7763 + // be synchronous since we will be checking the caret position on the screen. 1.7764 + // 1.7765 + // Be easy about errors, and just don't scroll in those cases. Better to have 1.7766 + // the correct menu at a weird place than the wrong menu. 1.7767 + // After ScrollSelectionIntoView(), the pending notifications might be 1.7768 + // flushed and PresShell/PresContext/Frames may be dead. See bug 418470. 1.7769 + nsCOMPtr<nsISelectionController> selCon; 1.7770 + if (frame) 1.7771 + frame->GetSelectionController(GetPresContext(), getter_AddRefs(selCon)); 1.7772 + else 1.7773 + selCon = static_cast<nsISelectionController *>(this); 1.7774 + if (selCon) { 1.7775 + rv = selCon->ScrollSelectionIntoView(nsISelectionController::SELECTION_NORMAL, 1.7776 + nsISelectionController::SELECTION_FOCUS_REGION, 1.7777 + nsISelectionController::SCROLL_SYNCHRONOUS); 1.7778 + NS_ENSURE_SUCCESS(rv, false); 1.7779 + } 1.7780 + 1.7781 + nsPresContext* presContext = GetPresContext(); 1.7782 + 1.7783 + // get caret position relative to the closest view 1.7784 + nsRect caretCoords; 1.7785 + nsIFrame* caretFrame = caret->GetGeometry(domSelection, &caretCoords); 1.7786 + if (!caretFrame) 1.7787 + return false; 1.7788 + nsPoint viewOffset; 1.7789 + nsView* view = caretFrame->GetClosestView(&viewOffset); 1.7790 + if (!view) 1.7791 + return false; 1.7792 + // and then get the caret coords relative to the event widget 1.7793 + if (aEventWidget) { 1.7794 + viewOffset += view->GetOffsetToWidget(aEventWidget); 1.7795 + } 1.7796 + caretCoords.MoveBy(viewOffset); 1.7797 + 1.7798 + // caret coordinates are in app units, convert to pixels 1.7799 + aTargetPt.x = 1.7800 + presContext->AppUnitsToDevPixels(caretCoords.x + caretCoords.width); 1.7801 + aTargetPt.y = 1.7802 + presContext->AppUnitsToDevPixels(caretCoords.y + caretCoords.height); 1.7803 + 1.7804 + // make sure rounding doesn't return a pixel which is outside the caret 1.7805 + // (e.g. one line lower) 1.7806 + aTargetPt.y -= 1; 1.7807 + 1.7808 + return true; 1.7809 +} 1.7810 + 1.7811 +void 1.7812 +PresShell::GetCurrentItemAndPositionForElement(nsIDOMElement *aCurrentEl, 1.7813 + nsIContent** aTargetToUse, 1.7814 + LayoutDeviceIntPoint& aTargetPt, 1.7815 + nsIWidget *aRootWidget) 1.7816 +{ 1.7817 + nsCOMPtr<nsIContent> focusedContent(do_QueryInterface(aCurrentEl)); 1.7818 + ScrollContentIntoView(focusedContent, 1.7819 + ScrollAxis(), 1.7820 + ScrollAxis(), 1.7821 + nsIPresShell::SCROLL_OVERFLOW_HIDDEN); 1.7822 + 1.7823 + nsPresContext* presContext = GetPresContext(); 1.7824 + 1.7825 + bool istree = false, checkLineHeight = true; 1.7826 + nscoord extraTreeY = 0; 1.7827 + 1.7828 +#ifdef MOZ_XUL 1.7829 + // Set the position to just underneath the current item for multi-select 1.7830 + // lists or just underneath the selected item for single-select lists. If 1.7831 + // the element is not a list, or there is no selection, leave the position 1.7832 + // as is. 1.7833 + nsCOMPtr<nsIDOMXULSelectControlItemElement> item; 1.7834 + nsCOMPtr<nsIDOMXULMultiSelectControlElement> multiSelect = 1.7835 + do_QueryInterface(aCurrentEl); 1.7836 + if (multiSelect) { 1.7837 + checkLineHeight = false; 1.7838 + 1.7839 + int32_t currentIndex; 1.7840 + multiSelect->GetCurrentIndex(¤tIndex); 1.7841 + if (currentIndex >= 0) { 1.7842 + nsCOMPtr<nsIDOMXULElement> xulElement(do_QueryInterface(aCurrentEl)); 1.7843 + if (xulElement) { 1.7844 + nsCOMPtr<nsIBoxObject> box; 1.7845 + xulElement->GetBoxObject(getter_AddRefs(box)); 1.7846 + nsCOMPtr<nsITreeBoxObject> treeBox(do_QueryInterface(box)); 1.7847 + // Tree view special case (tree items have no frames) 1.7848 + // Get the focused row and add its coordinates, which are already in pixels 1.7849 + // XXX Boris, should we create a new interface so that this doesn't 1.7850 + // need to know about trees? Something like nsINodelessChildCreator which 1.7851 + // could provide the current focus coordinates? 1.7852 + if (treeBox) { 1.7853 + treeBox->EnsureRowIsVisible(currentIndex); 1.7854 + int32_t firstVisibleRow, rowHeight; 1.7855 + treeBox->GetFirstVisibleRow(&firstVisibleRow); 1.7856 + treeBox->GetRowHeight(&rowHeight); 1.7857 + 1.7858 + extraTreeY += presContext->CSSPixelsToAppUnits( 1.7859 + (currentIndex - firstVisibleRow + 1) * rowHeight); 1.7860 + istree = true; 1.7861 + 1.7862 + nsCOMPtr<nsITreeColumns> cols; 1.7863 + treeBox->GetColumns(getter_AddRefs(cols)); 1.7864 + if (cols) { 1.7865 + nsCOMPtr<nsITreeColumn> col; 1.7866 + cols->GetFirstColumn(getter_AddRefs(col)); 1.7867 + if (col) { 1.7868 + nsCOMPtr<nsIDOMElement> colElement; 1.7869 + col->GetElement(getter_AddRefs(colElement)); 1.7870 + nsCOMPtr<nsIContent> colContent(do_QueryInterface(colElement)); 1.7871 + if (colContent) { 1.7872 + nsIFrame* frame = colContent->GetPrimaryFrame(); 1.7873 + if (frame) { 1.7874 + extraTreeY += frame->GetSize().height; 1.7875 + } 1.7876 + } 1.7877 + } 1.7878 + } 1.7879 + } 1.7880 + else { 1.7881 + multiSelect->GetCurrentItem(getter_AddRefs(item)); 1.7882 + } 1.7883 + } 1.7884 + } 1.7885 + } 1.7886 + else { 1.7887 + // don't check menulists as the selected item will be inside a popup. 1.7888 + nsCOMPtr<nsIDOMXULMenuListElement> menulist = do_QueryInterface(aCurrentEl); 1.7889 + if (!menulist) { 1.7890 + nsCOMPtr<nsIDOMXULSelectControlElement> select = 1.7891 + do_QueryInterface(aCurrentEl); 1.7892 + if (select) { 1.7893 + checkLineHeight = false; 1.7894 + select->GetSelectedItem(getter_AddRefs(item)); 1.7895 + } 1.7896 + } 1.7897 + } 1.7898 + 1.7899 + if (item) 1.7900 + focusedContent = do_QueryInterface(item); 1.7901 +#endif 1.7902 + 1.7903 + nsIFrame *frame = focusedContent->GetPrimaryFrame(); 1.7904 + if (frame) { 1.7905 + NS_ASSERTION(frame->PresContext() == GetPresContext(), 1.7906 + "handling event for focused content that is not in our document?"); 1.7907 + 1.7908 + nsPoint frameOrigin(0, 0); 1.7909 + 1.7910 + // Get the frame's origin within its view 1.7911 + nsView *view = frame->GetClosestView(&frameOrigin); 1.7912 + NS_ASSERTION(view, "No view for frame"); 1.7913 + 1.7914 + // View's origin relative the widget 1.7915 + if (aRootWidget) { 1.7916 + frameOrigin += view->GetOffsetToWidget(aRootWidget); 1.7917 + } 1.7918 + 1.7919 + // Start context menu down and to the right from top left of frame 1.7920 + // use the lineheight. This is a good distance to move the context 1.7921 + // menu away from the top left corner of the frame. If we always 1.7922 + // used the frame height, the context menu could end up far away, 1.7923 + // for example when we're focused on linked images. 1.7924 + // On the other hand, we want to use the frame height if it's less 1.7925 + // than the current line height, so that the context menu appears 1.7926 + // associated with the correct frame. 1.7927 + nscoord extra = 0; 1.7928 + if (!istree) { 1.7929 + extra = frame->GetSize().height; 1.7930 + if (checkLineHeight) { 1.7931 + nsIScrollableFrame *scrollFrame = 1.7932 + nsLayoutUtils::GetNearestScrollableFrame(frame); 1.7933 + if (scrollFrame) { 1.7934 + nsSize scrollAmount = scrollFrame->GetLineScrollAmount(); 1.7935 + nsIFrame* f = do_QueryFrame(scrollFrame); 1.7936 + int32_t APD = presContext->AppUnitsPerDevPixel(); 1.7937 + int32_t scrollAPD = f->PresContext()->AppUnitsPerDevPixel(); 1.7938 + scrollAmount = scrollAmount.ConvertAppUnits(scrollAPD, APD); 1.7939 + if (extra > scrollAmount.height) { 1.7940 + extra = scrollAmount.height; 1.7941 + } 1.7942 + } 1.7943 + } 1.7944 + } 1.7945 + 1.7946 + aTargetPt.x = presContext->AppUnitsToDevPixels(frameOrigin.x); 1.7947 + aTargetPt.y = presContext->AppUnitsToDevPixels( 1.7948 + frameOrigin.y + extra + extraTreeY); 1.7949 + } 1.7950 + 1.7951 + NS_IF_ADDREF(*aTargetToUse = focusedContent); 1.7952 +} 1.7953 + 1.7954 +bool 1.7955 +PresShell::ShouldIgnoreInvalidation() 1.7956 +{ 1.7957 + return mPaintingSuppressed || !mIsActive || mIsNeverPainting; 1.7958 +} 1.7959 + 1.7960 +void 1.7961 +PresShell::WillPaint() 1.7962 +{ 1.7963 + nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext(); 1.7964 + if (!rootPresContext) { 1.7965 + // In some edge cases, such as when we don't have a root frame yet, 1.7966 + // we can't find the root prescontext. There's nothing to do in that 1.7967 + // case. 1.7968 + return; 1.7969 + } 1.7970 + 1.7971 + // Don't bother doing anything if some viewmanager in our tree is painting 1.7972 + // while we still have painting suppressed or we are not active. 1.7973 + if (mPaintingSuppressed || !mIsActive || !IsVisible()) { 1.7974 + return; 1.7975 + } 1.7976 + 1.7977 + rootPresContext->FlushWillPaintObservers(); 1.7978 + if (mIsDestroying) 1.7979 + return; 1.7980 + 1.7981 + // Process reflows, if we have them, to reduce flicker due to invalidates and 1.7982 + // reflow being interspersed. Note that we _do_ allow this to be 1.7983 + // interruptible; if we can't do all the reflows it's better to flicker a bit 1.7984 + // than to freeze up. 1.7985 + FlushPendingNotifications(ChangesToFlush(Flush_InterruptibleLayout, false)); 1.7986 +} 1.7987 + 1.7988 +void 1.7989 +PresShell::WillPaintWindow() 1.7990 +{ 1.7991 + nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext(); 1.7992 + if (rootPresContext != mPresContext) { 1.7993 + // This could be a popup's presshell. We don't allow plugins in popups 1.7994 + // so there's nothing to do here. 1.7995 + return; 1.7996 + } 1.7997 + 1.7998 +#ifndef XP_MACOSX 1.7999 + rootPresContext->ApplyPluginGeometryUpdates(); 1.8000 +#endif 1.8001 +} 1.8002 + 1.8003 +void 1.8004 +PresShell::DidPaintWindow() 1.8005 +{ 1.8006 + nsRootPresContext* rootPresContext = mPresContext->GetRootPresContext(); 1.8007 + if (rootPresContext != mPresContext) { 1.8008 + // This could be a popup's presshell. No point in notifying XPConnect 1.8009 + // about compositing of popups. 1.8010 + return; 1.8011 + } 1.8012 + 1.8013 + if (nsContentUtils::XPConnect()) { 1.8014 + nsContentUtils::XPConnect()->NotifyDidPaint(); 1.8015 + } 1.8016 +} 1.8017 + 1.8018 +bool 1.8019 +PresShell::IsVisible() 1.8020 +{ 1.8021 + if (!mViewManager) 1.8022 + return false; 1.8023 + 1.8024 + nsView* view = mViewManager->GetRootView(); 1.8025 + if (!view) 1.8026 + return true; 1.8027 + 1.8028 + // inner view of subdoc frame 1.8029 + view = view->GetParent(); 1.8030 + if (!view) 1.8031 + return true; 1.8032 + 1.8033 + // subdoc view 1.8034 + view = view->GetParent(); 1.8035 + if (!view) 1.8036 + return true; 1.8037 + 1.8038 + nsIFrame* frame = view->GetFrame(); 1.8039 + if (!frame) 1.8040 + return true; 1.8041 + 1.8042 + return frame->IsVisibleConsideringAncestors(nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY); 1.8043 +} 1.8044 + 1.8045 +nsresult 1.8046 +PresShell::GetAgentStyleSheets(nsCOMArray<nsIStyleSheet>& aSheets) 1.8047 +{ 1.8048 + aSheets.Clear(); 1.8049 + int32_t sheetCount = mStyleSet->SheetCount(nsStyleSet::eAgentSheet); 1.8050 + 1.8051 + for (int32_t i = 0; i < sheetCount; ++i) { 1.8052 + nsIStyleSheet *sheet = mStyleSet->StyleSheetAt(nsStyleSet::eAgentSheet, i); 1.8053 + if (!aSheets.AppendObject(sheet)) 1.8054 + return NS_ERROR_OUT_OF_MEMORY; 1.8055 + } 1.8056 + 1.8057 + return NS_OK; 1.8058 +} 1.8059 + 1.8060 +nsresult 1.8061 +PresShell::SetAgentStyleSheets(const nsCOMArray<nsIStyleSheet>& aSheets) 1.8062 +{ 1.8063 + return mStyleSet->ReplaceSheets(nsStyleSet::eAgentSheet, aSheets); 1.8064 +} 1.8065 + 1.8066 +nsresult 1.8067 +PresShell::AddOverrideStyleSheet(nsIStyleSheet *aSheet) 1.8068 +{ 1.8069 + return mStyleSet->PrependStyleSheet(nsStyleSet::eOverrideSheet, aSheet); 1.8070 +} 1.8071 + 1.8072 +nsresult 1.8073 +PresShell::RemoveOverrideStyleSheet(nsIStyleSheet *aSheet) 1.8074 +{ 1.8075 + return mStyleSet->RemoveStyleSheet(nsStyleSet::eOverrideSheet, aSheet); 1.8076 +} 1.8077 + 1.8078 +static void 1.8079 +FreezeElement(nsIContent *aContent, void * /* unused */) 1.8080 +{ 1.8081 + nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent)); 1.8082 + if (olc) { 1.8083 + olc->StopPluginInstance(); 1.8084 + } 1.8085 +} 1.8086 + 1.8087 +static bool 1.8088 +FreezeSubDocument(nsIDocument *aDocument, void *aData) 1.8089 +{ 1.8090 + nsIPresShell *shell = aDocument->GetShell(); 1.8091 + if (shell) 1.8092 + shell->Freeze(); 1.8093 + 1.8094 + return true; 1.8095 +} 1.8096 + 1.8097 +void 1.8098 +PresShell::Freeze() 1.8099 +{ 1.8100 + mUpdateImageVisibilityEvent.Revoke(); 1.8101 + 1.8102 + MaybeReleaseCapturingContent(); 1.8103 + 1.8104 + mDocument->EnumerateFreezableElements(FreezeElement, nullptr); 1.8105 + 1.8106 + if (mCaret) { 1.8107 + mCaret->SetCaretVisible(false); 1.8108 + } 1.8109 + 1.8110 + mPaintingSuppressed = true; 1.8111 + 1.8112 + if (mDocument) { 1.8113 + mDocument->EnumerateSubDocuments(FreezeSubDocument, nullptr); 1.8114 + } 1.8115 + 1.8116 + nsPresContext* presContext = GetPresContext(); 1.8117 + if (presContext && 1.8118 + presContext->RefreshDriver()->PresContext() == presContext) { 1.8119 + presContext->RefreshDriver()->Freeze(); 1.8120 + } 1.8121 + 1.8122 + mFrozen = true; 1.8123 + if (mDocument) { 1.8124 + UpdateImageLockingState(); 1.8125 + } 1.8126 +} 1.8127 + 1.8128 +void 1.8129 +PresShell::FireOrClearDelayedEvents(bool aFireEvents) 1.8130 +{ 1.8131 + mNoDelayedMouseEvents = false; 1.8132 + mNoDelayedKeyEvents = false; 1.8133 + if (!aFireEvents) { 1.8134 + mDelayedEvents.Clear(); 1.8135 + return; 1.8136 + } 1.8137 + 1.8138 + if (mDocument) { 1.8139 + nsCOMPtr<nsIDocument> doc = mDocument; 1.8140 + while (!mIsDestroying && mDelayedEvents.Length() && 1.8141 + !doc->EventHandlingSuppressed()) { 1.8142 + nsAutoPtr<DelayedEvent> ev(mDelayedEvents[0].forget()); 1.8143 + mDelayedEvents.RemoveElementAt(0); 1.8144 + ev->Dispatch(); 1.8145 + } 1.8146 + if (!doc->EventHandlingSuppressed()) { 1.8147 + mDelayedEvents.Clear(); 1.8148 + } 1.8149 + } 1.8150 +} 1.8151 + 1.8152 +static void 1.8153 +ThawElement(nsIContent *aContent, void *aShell) 1.8154 +{ 1.8155 + nsCOMPtr<nsIObjectLoadingContent> olc(do_QueryInterface(aContent)); 1.8156 + if (olc) { 1.8157 + olc->AsyncStartPluginInstance(); 1.8158 + } 1.8159 +} 1.8160 + 1.8161 +static bool 1.8162 +ThawSubDocument(nsIDocument *aDocument, void *aData) 1.8163 +{ 1.8164 + nsIPresShell *shell = aDocument->GetShell(); 1.8165 + if (shell) 1.8166 + shell->Thaw(); 1.8167 + 1.8168 + return true; 1.8169 +} 1.8170 + 1.8171 +void 1.8172 +PresShell::Thaw() 1.8173 +{ 1.8174 + nsPresContext* presContext = GetPresContext(); 1.8175 + if (presContext && 1.8176 + presContext->RefreshDriver()->PresContext() == presContext) { 1.8177 + presContext->RefreshDriver()->Thaw(); 1.8178 + } 1.8179 + 1.8180 + mDocument->EnumerateFreezableElements(ThawElement, this); 1.8181 + 1.8182 + if (mDocument) 1.8183 + mDocument->EnumerateSubDocuments(ThawSubDocument, nullptr); 1.8184 + 1.8185 + // Get the activeness of our presshell, as this might have changed 1.8186 + // while we were in the bfcache 1.8187 + QueryIsActive(); 1.8188 + 1.8189 + // We're now unfrozen 1.8190 + mFrozen = false; 1.8191 + UpdateImageLockingState(); 1.8192 + 1.8193 + UnsuppressPainting(); 1.8194 +} 1.8195 + 1.8196 +//-------------------------------------------------------- 1.8197 +// Start of protected and private methods on the PresShell 1.8198 +//-------------------------------------------------------- 1.8199 + 1.8200 +void 1.8201 +PresShell::MaybeScheduleReflow() 1.8202 +{ 1.8203 + ASSERT_REFLOW_SCHEDULED_STATE(); 1.8204 + if (mReflowScheduled || mIsDestroying || mIsReflowing || 1.8205 + mDirtyRoots.Length() == 0) 1.8206 + return; 1.8207 + 1.8208 + if (!mPresContext->HasPendingInterrupt() || !ScheduleReflowOffTimer()) { 1.8209 + ScheduleReflow(); 1.8210 + } 1.8211 + 1.8212 + ASSERT_REFLOW_SCHEDULED_STATE(); 1.8213 +} 1.8214 + 1.8215 +void 1.8216 +PresShell::ScheduleReflow() 1.8217 +{ 1.8218 + NS_PRECONDITION(!mReflowScheduled, "Why are we trying to schedule a reflow?"); 1.8219 + ASSERT_REFLOW_SCHEDULED_STATE(); 1.8220 + 1.8221 + if (GetPresContext()->RefreshDriver()->AddLayoutFlushObserver(this)) { 1.8222 + mReflowScheduled = true; 1.8223 + } 1.8224 + 1.8225 + ASSERT_REFLOW_SCHEDULED_STATE(); 1.8226 +} 1.8227 + 1.8228 +nsresult 1.8229 +PresShell::DidCauseReflow() 1.8230 +{ 1.8231 + NS_ASSERTION(mChangeNestCount != 0, "Unexpected call to DidCauseReflow()"); 1.8232 + --mChangeNestCount; 1.8233 + nsContentUtils::RemoveScriptBlocker(); 1.8234 + 1.8235 + return NS_OK; 1.8236 +} 1.8237 + 1.8238 +void 1.8239 +PresShell::WillDoReflow() 1.8240 +{ 1.8241 + // We just reflowed, tell the caret that its frame might have moved. 1.8242 + // XXXbz that comment makes no sense 1.8243 + if (mCaret) { 1.8244 + mCaret->InvalidateOutsideCaret(); 1.8245 + } 1.8246 + 1.8247 + mPresContext->FlushUserFontSet(); 1.8248 + 1.8249 + mFrameConstructor->BeginUpdate(); 1.8250 + 1.8251 + mLastReflowStart = GetPerformanceNow(); 1.8252 +} 1.8253 + 1.8254 +void 1.8255 +PresShell::DidDoReflow(bool aInterruptible, bool aWasInterrupted) 1.8256 +{ 1.8257 + mFrameConstructor->EndUpdate(); 1.8258 + 1.8259 + HandlePostedReflowCallbacks(aInterruptible); 1.8260 + 1.8261 + nsCOMPtr<nsIDocShell> docShell = mPresContext->GetDocShell(); 1.8262 + if (docShell) { 1.8263 + DOMHighResTimeStamp now = GetPerformanceNow(); 1.8264 + docShell->NotifyReflowObservers(aInterruptible, mLastReflowStart, now); 1.8265 + } 1.8266 + 1.8267 + if (sSynthMouseMove) { 1.8268 + SynthesizeMouseMove(false); 1.8269 + } 1.8270 + if (mCaret) { 1.8271 + // Update the caret's position now to account for any changes created by 1.8272 + // the reflow. 1.8273 + mCaret->InvalidateOutsideCaret(); 1.8274 + mCaret->UpdateCaretPosition(); 1.8275 + } 1.8276 + 1.8277 + if (!aWasInterrupted) { 1.8278 + ClearReflowOnZoomPending(); 1.8279 + } 1.8280 +} 1.8281 + 1.8282 +DOMHighResTimeStamp 1.8283 +PresShell::GetPerformanceNow() 1.8284 +{ 1.8285 + DOMHighResTimeStamp now = 0; 1.8286 + nsPIDOMWindow* window = mDocument->GetInnerWindow(); 1.8287 + 1.8288 + if (window) { 1.8289 + nsPerformance* perf = window->GetPerformance(); 1.8290 + 1.8291 + if (perf) { 1.8292 + now = perf->Now(); 1.8293 + } 1.8294 + } 1.8295 + 1.8296 + return now; 1.8297 +} 1.8298 + 1.8299 +static PLDHashOperator 1.8300 +MarkFramesDirtyToRoot(nsPtrHashKey<nsIFrame>* p, void* closure) 1.8301 +{ 1.8302 + nsIFrame* target = static_cast<nsIFrame*>(closure); 1.8303 + for (nsIFrame* f = p->GetKey(); f && !NS_SUBTREE_DIRTY(f); 1.8304 + f = f->GetParent()) { 1.8305 + f->AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN); 1.8306 + 1.8307 + if (f == target) { 1.8308 + break; 1.8309 + } 1.8310 + } 1.8311 + 1.8312 + return PL_DHASH_NEXT; 1.8313 +} 1.8314 + 1.8315 +void 1.8316 +PresShell::sReflowContinueCallback(nsITimer* aTimer, void* aPresShell) 1.8317 +{ 1.8318 + nsRefPtr<PresShell> self = static_cast<PresShell*>(aPresShell); 1.8319 + 1.8320 + NS_PRECONDITION(aTimer == self->mReflowContinueTimer, "Unexpected timer"); 1.8321 + self->mReflowContinueTimer = nullptr; 1.8322 + self->ScheduleReflow(); 1.8323 +} 1.8324 + 1.8325 +bool 1.8326 +PresShell::ScheduleReflowOffTimer() 1.8327 +{ 1.8328 + NS_PRECONDITION(!mReflowScheduled, "Shouldn't get here"); 1.8329 + ASSERT_REFLOW_SCHEDULED_STATE(); 1.8330 + 1.8331 + if (!mReflowContinueTimer) { 1.8332 + mReflowContinueTimer = do_CreateInstance("@mozilla.org/timer;1"); 1.8333 + if (!mReflowContinueTimer || 1.8334 + NS_FAILED(mReflowContinueTimer-> 1.8335 + InitWithFuncCallback(sReflowContinueCallback, this, 30, 1.8336 + nsITimer::TYPE_ONE_SHOT))) { 1.8337 + return false; 1.8338 + } 1.8339 + } 1.8340 + return true; 1.8341 +} 1.8342 + 1.8343 +bool 1.8344 +PresShell::DoReflow(nsIFrame* target, bool aInterruptible) 1.8345 +{ 1.8346 + if (mIsZombie) { 1.8347 + return true; 1.8348 + } 1.8349 + 1.8350 + gfxTextPerfMetrics* tp = mPresContext->GetTextPerfMetrics(); 1.8351 + TimeStamp timeStart; 1.8352 + if (tp) { 1.8353 + tp->Accumulate(); 1.8354 + tp->reflowCount++; 1.8355 + timeStart = TimeStamp::Now(); 1.8356 + } 1.8357 + 1.8358 + target->SchedulePaint(); 1.8359 + nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(target); 1.8360 + while (parent) { 1.8361 + nsSVGEffects::InvalidateDirectRenderingObservers(parent); 1.8362 + parent = nsLayoutUtils::GetCrossDocParentFrame(parent); 1.8363 + } 1.8364 + 1.8365 + nsAutoCString docURL("N/A"); 1.8366 + nsIURI *uri = mDocument->GetDocumentURI(); 1.8367 + if (uri) 1.8368 + uri->GetSpec(docURL); 1.8369 + PROFILER_LABEL_PRINTF("layout", "DoReflow", "(%s)", docURL.get()); 1.8370 + 1.8371 + if (mReflowContinueTimer) { 1.8372 + mReflowContinueTimer->Cancel(); 1.8373 + mReflowContinueTimer = nullptr; 1.8374 + } 1.8375 + 1.8376 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.8377 + 1.8378 + nsRefPtr<nsRenderingContext> rcx = CreateReferenceRenderingContext(); 1.8379 + 1.8380 +#ifdef DEBUG 1.8381 + mCurrentReflowRoot = target; 1.8382 +#endif 1.8383 + 1.8384 + target->WillReflow(mPresContext); 1.8385 + 1.8386 + // If the target frame is the root of the frame hierarchy, then 1.8387 + // use all the available space. If it's simply a `reflow root', 1.8388 + // then use the target frame's size as the available space. 1.8389 + nsSize size; 1.8390 + if (target == rootFrame) { 1.8391 + size = mPresContext->GetVisibleArea().Size(); 1.8392 + } else { 1.8393 + size = target->GetSize(); 1.8394 + } 1.8395 + 1.8396 + NS_ASSERTION(!target->GetNextInFlow() && !target->GetPrevInFlow(), 1.8397 + "reflow roots should never split"); 1.8398 + 1.8399 + // Don't pass size directly to the reflow state, since a 1.8400 + // constrained height implies page/column breaking. 1.8401 + nsSize reflowSize(size.width, NS_UNCONSTRAINEDSIZE); 1.8402 + nsHTMLReflowState reflowState(mPresContext, target, rcx, reflowSize, 1.8403 + nsHTMLReflowState::CALLER_WILL_INIT); 1.8404 + 1.8405 + if (rootFrame == target) { 1.8406 + reflowState.Init(mPresContext); 1.8407 + 1.8408 + // When the root frame is being reflowed with unconstrained height 1.8409 + // (which happens when we're called from 1.8410 + // nsDocumentViewer::SizeToContent), we're effectively doing a 1.8411 + // vertical resize, since it changes the meaning of percentage 1.8412 + // heights even if no heights actually changed. The same applies 1.8413 + // when we reflow again after that computation. This is an unusual 1.8414 + // case, and isn't caught by nsHTMLReflowState::InitResizeFlags. 1.8415 + bool hasUnconstrainedHeight = size.height == NS_UNCONSTRAINEDSIZE; 1.8416 + 1.8417 + if (hasUnconstrainedHeight || mLastRootReflowHadUnconstrainedHeight) { 1.8418 + reflowState.mFlags.mVResize = true; 1.8419 + } 1.8420 + 1.8421 + mLastRootReflowHadUnconstrainedHeight = hasUnconstrainedHeight; 1.8422 + } else { 1.8423 + // Initialize reflow state with current used border and padding, 1.8424 + // in case this was set specially by the parent frame when the reflow root 1.8425 + // was reflowed by its parent. 1.8426 + nsMargin currentBorder = target->GetUsedBorder(); 1.8427 + nsMargin currentPadding = target->GetUsedPadding(); 1.8428 + reflowState.Init(mPresContext, -1, -1, ¤tBorder, ¤tPadding); 1.8429 + } 1.8430 + 1.8431 + // fix the computed height 1.8432 + NS_ASSERTION(reflowState.ComputedPhysicalMargin() == nsMargin(0, 0, 0, 0), 1.8433 + "reflow state should not set margin for reflow roots"); 1.8434 + if (size.height != NS_UNCONSTRAINEDSIZE) { 1.8435 + nscoord computedHeight = 1.8436 + size.height - reflowState.ComputedPhysicalBorderPadding().TopBottom(); 1.8437 + computedHeight = std::max(computedHeight, 0); 1.8438 + reflowState.SetComputedHeight(computedHeight); 1.8439 + } 1.8440 + NS_ASSERTION(reflowState.ComputedWidth() == 1.8441 + size.width - 1.8442 + reflowState.ComputedPhysicalBorderPadding().LeftRight(), 1.8443 + "reflow state computed incorrect width"); 1.8444 + 1.8445 + mPresContext->ReflowStarted(aInterruptible); 1.8446 + mIsReflowing = true; 1.8447 + 1.8448 + nsReflowStatus status; 1.8449 + nsHTMLReflowMetrics desiredSize(reflowState); 1.8450 + target->Reflow(mPresContext, desiredSize, reflowState, status); 1.8451 + 1.8452 + // If an incremental reflow is initiated at a frame other than the 1.8453 + // root frame, then its desired size had better not change! If it's 1.8454 + // initiated at the root, then the size better not change unless its 1.8455 + // height was unconstrained to start with. 1.8456 + nsRect boundsRelativeToTarget = nsRect(0, 0, desiredSize.Width(), desiredSize.Height()); 1.8457 + NS_ASSERTION((target == rootFrame && size.height == NS_UNCONSTRAINEDSIZE) || 1.8458 + (desiredSize.Width() == size.width && 1.8459 + desiredSize.Height() == size.height), 1.8460 + "non-root frame's desired size changed during an " 1.8461 + "incremental reflow"); 1.8462 + NS_ASSERTION(target == rootFrame || 1.8463 + desiredSize.VisualOverflow().IsEqualInterior(boundsRelativeToTarget), 1.8464 + "non-root reflow roots must not have visible overflow"); 1.8465 + NS_ASSERTION(target == rootFrame || 1.8466 + desiredSize.ScrollableOverflow().IsEqualEdges(boundsRelativeToTarget), 1.8467 + "non-root reflow roots must not have scrollable overflow"); 1.8468 + NS_ASSERTION(status == NS_FRAME_COMPLETE, 1.8469 + "reflow roots should never split"); 1.8470 + 1.8471 + target->SetSize(boundsRelativeToTarget.Size()); 1.8472 + 1.8473 + // Always use boundsRelativeToTarget here, not desiredSize.GetVisualOverflowArea(), 1.8474 + // because for root frames (where they could be different, since root frames 1.8475 + // are allowed to have overflow) the root view bounds need to match the 1.8476 + // viewport bounds; the view manager "window dimensions" code depends on it. 1.8477 + nsContainerFrame::SyncFrameViewAfterReflow(mPresContext, target, 1.8478 + target->GetView(), 1.8479 + boundsRelativeToTarget); 1.8480 + nsContainerFrame::SyncWindowProperties(mPresContext, target, 1.8481 + target->GetView(), rcx); 1.8482 + 1.8483 + target->DidReflow(mPresContext, nullptr, nsDidReflowStatus::FINISHED); 1.8484 + if (target == rootFrame && size.height == NS_UNCONSTRAINEDSIZE) { 1.8485 + mPresContext->SetVisibleArea(boundsRelativeToTarget); 1.8486 + } 1.8487 + 1.8488 +#ifdef DEBUG 1.8489 + mCurrentReflowRoot = nullptr; 1.8490 +#endif 1.8491 + 1.8492 + NS_ASSERTION(mPresContext->HasPendingInterrupt() || 1.8493 + mFramesToDirty.Count() == 0, 1.8494 + "Why do we need to dirty anything if not interrupted?"); 1.8495 + 1.8496 + mIsReflowing = false; 1.8497 + bool interrupted = mPresContext->HasPendingInterrupt(); 1.8498 + if (interrupted) { 1.8499 + // Make sure target gets reflowed again. 1.8500 + mFramesToDirty.EnumerateEntries(&MarkFramesDirtyToRoot, target); 1.8501 + NS_ASSERTION(NS_SUBTREE_DIRTY(target), "Why is the target not dirty?"); 1.8502 + mDirtyRoots.AppendElement(target); 1.8503 + mDocument->SetNeedLayoutFlush(); 1.8504 + 1.8505 + // Clear mFramesToDirty after we've done the NS_SUBTREE_DIRTY(target) 1.8506 + // assertion so that if it fails it's easier to see what's going on. 1.8507 +#ifdef NOISY_INTERRUPTIBLE_REFLOW 1.8508 + printf("mFramesToDirty.Count() == %u\n", mFramesToDirty.Count()); 1.8509 +#endif /* NOISY_INTERRUPTIBLE_REFLOW */ 1.8510 + mFramesToDirty.Clear(); 1.8511 + 1.8512 + // Any FlushPendingNotifications with interruptible reflows 1.8513 + // should be suppressed now. We don't want to do extra reflow work 1.8514 + // before our reflow event happens. 1.8515 + mSuppressInterruptibleReflows = true; 1.8516 + MaybeScheduleReflow(); 1.8517 + } 1.8518 + 1.8519 +#ifdef PR_LOGGING 1.8520 + // dump text perf metrics for reflows with significant text processing 1.8521 + if (tp) { 1.8522 + if (tp->current.numChars > 100) { 1.8523 + TimeDuration reflowTime = TimeStamp::Now() - timeStart; 1.8524 + LogTextPerfStats(tp, this, tp->current, 1.8525 + reflowTime.ToMilliseconds(), eLog_reflow, nullptr); 1.8526 + } 1.8527 + tp->Accumulate(); 1.8528 + } 1.8529 +#endif 1.8530 + 1.8531 + return !interrupted; 1.8532 +} 1.8533 + 1.8534 +#ifdef DEBUG 1.8535 +void 1.8536 +PresShell::DoVerifyReflow() 1.8537 +{ 1.8538 + if (GetVerifyReflowEnable()) { 1.8539 + // First synchronously render what we have so far so that we can 1.8540 + // see it. 1.8541 + nsView* rootView = mViewManager->GetRootView(); 1.8542 + mViewManager->InvalidateView(rootView); 1.8543 + 1.8544 + FlushPendingNotifications(Flush_Layout); 1.8545 + mInVerifyReflow = true; 1.8546 + bool ok = VerifyIncrementalReflow(); 1.8547 + mInVerifyReflow = false; 1.8548 + if (VERIFY_REFLOW_ALL & gVerifyReflowFlags) { 1.8549 + printf("ProcessReflowCommands: finished (%s)\n", 1.8550 + ok ? "ok" : "failed"); 1.8551 + } 1.8552 + 1.8553 + if (!mDirtyRoots.IsEmpty()) { 1.8554 + printf("XXX yikes! reflow commands queued during verify-reflow\n"); 1.8555 + } 1.8556 + } 1.8557 +} 1.8558 +#endif 1.8559 + 1.8560 +// used with Telemetry metrics 1.8561 +#define NS_LONG_REFLOW_TIME_MS 5000 1.8562 + 1.8563 +bool 1.8564 +PresShell::ProcessReflowCommands(bool aInterruptible) 1.8565 +{ 1.8566 + if (mDirtyRoots.IsEmpty() && !mShouldUnsuppressPainting) { 1.8567 + // Nothing to do; bail out 1.8568 + return true; 1.8569 + } 1.8570 + 1.8571 + mozilla::TimeStamp timerStart = mozilla::TimeStamp::Now(); 1.8572 + bool interrupted = false; 1.8573 + if (!mDirtyRoots.IsEmpty()) { 1.8574 + 1.8575 +#ifdef DEBUG 1.8576 + if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) { 1.8577 + printf("ProcessReflowCommands: begin incremental reflow\n"); 1.8578 + } 1.8579 +#endif 1.8580 + 1.8581 + // If reflow is interruptible, then make a note of our deadline. 1.8582 + const PRIntervalTime deadline = aInterruptible 1.8583 + ? PR_IntervalNow() + PR_MicrosecondsToInterval(gMaxRCProcessingTime) 1.8584 + : (PRIntervalTime)0; 1.8585 + 1.8586 + // Scope for the reflow entry point 1.8587 + { 1.8588 + nsAutoScriptBlocker scriptBlocker; 1.8589 + WillDoReflow(); 1.8590 + AUTO_LAYOUT_PHASE_ENTRY_POINT(GetPresContext(), Reflow); 1.8591 + nsViewManager::AutoDisableRefresh refreshBlocker(mViewManager); 1.8592 + 1.8593 + do { 1.8594 + // Send an incremental reflow notification to the target frame. 1.8595 + int32_t idx = mDirtyRoots.Length() - 1; 1.8596 + nsIFrame *target = mDirtyRoots[idx]; 1.8597 + mDirtyRoots.RemoveElementAt(idx); 1.8598 + 1.8599 + if (!NS_SUBTREE_DIRTY(target)) { 1.8600 + // It's not dirty anymore, which probably means the notification 1.8601 + // was posted in the middle of a reflow (perhaps with a reflow 1.8602 + // root in the middle). Don't do anything. 1.8603 + continue; 1.8604 + } 1.8605 + 1.8606 + interrupted = !DoReflow(target, aInterruptible); 1.8607 + 1.8608 + // Keep going until we're out of reflow commands, or we've run 1.8609 + // past our deadline, or we're interrupted. 1.8610 + } while (!interrupted && !mDirtyRoots.IsEmpty() && 1.8611 + (!aInterruptible || PR_IntervalNow() < deadline)); 1.8612 + 1.8613 + interrupted = !mDirtyRoots.IsEmpty(); 1.8614 + } 1.8615 + 1.8616 + // Exiting the scriptblocker might have killed us 1.8617 + if (!mIsDestroying) { 1.8618 + DidDoReflow(aInterruptible, interrupted); 1.8619 + } 1.8620 + 1.8621 + // DidDoReflow might have killed us 1.8622 + if (!mIsDestroying) { 1.8623 +#ifdef DEBUG 1.8624 + if (VERIFY_REFLOW_DUMP_COMMANDS & gVerifyReflowFlags) { 1.8625 + printf("\nPresShell::ProcessReflowCommands() finished: this=%p\n", 1.8626 + (void*)this); 1.8627 + } 1.8628 + DoVerifyReflow(); 1.8629 +#endif 1.8630 + 1.8631 + // If any new reflow commands were enqueued during the reflow, schedule 1.8632 + // another reflow event to process them. Note that we want to do this 1.8633 + // after DidDoReflow(), since that method can change whether there are 1.8634 + // dirty roots around by flushing, and there's no point in posting a 1.8635 + // reflow event just to have the flush revoke it. 1.8636 + if (!mDirtyRoots.IsEmpty()) { 1.8637 + MaybeScheduleReflow(); 1.8638 + // And tell our document that we might need flushing 1.8639 + mDocument->SetNeedLayoutFlush(); 1.8640 + } 1.8641 + } 1.8642 + } 1.8643 + 1.8644 + if (!mIsDestroying && mShouldUnsuppressPainting && 1.8645 + mDirtyRoots.IsEmpty()) { 1.8646 + // We only unlock if we're out of reflows. It's pointless 1.8647 + // to unlock if reflows are still pending, since reflows 1.8648 + // are just going to thrash the frames around some more. By 1.8649 + // waiting we avoid an overeager "jitter" effect. 1.8650 + mShouldUnsuppressPainting = false; 1.8651 + UnsuppressAndInvalidate(); 1.8652 + } 1.8653 + 1.8654 + if (mDocument->GetRootElement()) { 1.8655 + TimeDuration elapsed = TimeStamp::Now() - timerStart; 1.8656 + int32_t intElapsed = int32_t(elapsed.ToMilliseconds()); 1.8657 + 1.8658 + Telemetry::ID id; 1.8659 + if (mDocument->GetRootElement()->IsXUL()) { 1.8660 + id = mIsActive 1.8661 + ? Telemetry::XUL_FOREGROUND_REFLOW_MS 1.8662 + : Telemetry::XUL_BACKGROUND_REFLOW_MS; 1.8663 + } else { 1.8664 + id = mIsActive 1.8665 + ? Telemetry::HTML_FOREGROUND_REFLOW_MS_2 1.8666 + : Telemetry::HTML_BACKGROUND_REFLOW_MS_2; 1.8667 + } 1.8668 + Telemetry::Accumulate(id, intElapsed); 1.8669 + if (intElapsed > NS_LONG_REFLOW_TIME_MS) { 1.8670 + Telemetry::Accumulate(Telemetry::LONG_REFLOW_INTERRUPTIBLE, 1.8671 + aInterruptible ? 1 : 0); 1.8672 + } 1.8673 + } 1.8674 + 1.8675 + return !interrupted; 1.8676 +} 1.8677 + 1.8678 +void 1.8679 +PresShell::WindowSizeMoveDone() 1.8680 +{ 1.8681 + if (mPresContext) { 1.8682 + EventStateManager::ClearGlobalActiveContent(nullptr); 1.8683 + ClearMouseCapture(nullptr); 1.8684 + } 1.8685 +} 1.8686 + 1.8687 +#ifdef MOZ_XUL 1.8688 +/* 1.8689 + * It's better to add stuff to the |DidSetStyleContext| method of the 1.8690 + * relevant frames than adding it here. These methods should (ideally, 1.8691 + * anyway) go away. 1.8692 + */ 1.8693 + 1.8694 +// Return value says whether to walk children. 1.8695 +typedef bool (* frameWalkerFn)(nsIFrame *aFrame, void *aClosure); 1.8696 + 1.8697 +static bool 1.8698 +ReResolveMenusAndTrees(nsIFrame *aFrame, void *aClosure) 1.8699 +{ 1.8700 + // Trees have a special style cache that needs to be flushed when 1.8701 + // the theme changes. 1.8702 + nsTreeBodyFrame *treeBody = do_QueryFrame(aFrame); 1.8703 + if (treeBody) 1.8704 + treeBody->ClearStyleAndImageCaches(); 1.8705 + 1.8706 + // We deliberately don't re-resolve style on a menu's popup 1.8707 + // sub-content, since doing so slows menus to a crawl. That means we 1.8708 + // have to special-case them on a skin switch, and ensure that the 1.8709 + // popup frames just get destroyed completely. 1.8710 + nsMenuFrame* menu = do_QueryFrame(aFrame); 1.8711 + if (menu) 1.8712 + menu->CloseMenu(true); 1.8713 + return true; 1.8714 +} 1.8715 + 1.8716 +static bool 1.8717 +ReframeImageBoxes(nsIFrame *aFrame, void *aClosure) 1.8718 +{ 1.8719 + nsStyleChangeList *list = static_cast<nsStyleChangeList*>(aClosure); 1.8720 + if (aFrame->GetType() == nsGkAtoms::imageBoxFrame) { 1.8721 + list->AppendChange(aFrame, aFrame->GetContent(), 1.8722 + NS_STYLE_HINT_FRAMECHANGE); 1.8723 + return false; // don't walk descendants 1.8724 + } 1.8725 + return true; // walk descendants 1.8726 +} 1.8727 + 1.8728 +static void 1.8729 +WalkFramesThroughPlaceholders(nsPresContext *aPresContext, nsIFrame *aFrame, 1.8730 + frameWalkerFn aFunc, void *aClosure) 1.8731 +{ 1.8732 + bool walkChildren = (*aFunc)(aFrame, aClosure); 1.8733 + if (!walkChildren) 1.8734 + return; 1.8735 + 1.8736 + nsIFrame::ChildListIterator lists(aFrame); 1.8737 + for (; !lists.IsDone(); lists.Next()) { 1.8738 + nsFrameList::Enumerator childFrames(lists.CurrentList()); 1.8739 + for (; !childFrames.AtEnd(); childFrames.Next()) { 1.8740 + nsIFrame* child = childFrames.get(); 1.8741 + if (!(child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { 1.8742 + // only do frames that are in flow, and recur through the 1.8743 + // out-of-flows of placeholders. 1.8744 + WalkFramesThroughPlaceholders(aPresContext, 1.8745 + nsPlaceholderFrame::GetRealFrameFor(child), 1.8746 + aFunc, aClosure); 1.8747 + } 1.8748 + } 1.8749 + } 1.8750 +} 1.8751 +#endif 1.8752 + 1.8753 +NS_IMETHODIMP 1.8754 +PresShell::Observe(nsISupports* aSubject, 1.8755 + const char* aTopic, 1.8756 + const char16_t* aData) 1.8757 +{ 1.8758 +#ifdef MOZ_XUL 1.8759 + if (!nsCRT::strcmp(aTopic, "chrome-flush-skin-caches")) { 1.8760 + nsIFrame *rootFrame = mFrameConstructor->GetRootFrame(); 1.8761 + // Need to null-check because "chrome-flush-skin-caches" can happen 1.8762 + // at interesting times during startup. 1.8763 + if (rootFrame) { 1.8764 + NS_ASSERTION(mViewManager, "View manager must exist"); 1.8765 + 1.8766 + nsWeakFrame weakRoot(rootFrame); 1.8767 + // Have to make sure that the content notifications are flushed before we 1.8768 + // start messing with the frame model; otherwise we can get content doubling. 1.8769 + mDocument->FlushPendingNotifications(Flush_ContentAndNotify); 1.8770 + 1.8771 + if (weakRoot.IsAlive()) { 1.8772 + WalkFramesThroughPlaceholders(mPresContext, rootFrame, 1.8773 + &ReResolveMenusAndTrees, nullptr); 1.8774 + 1.8775 + // Because "chrome:" URL equality is messy, reframe image box 1.8776 + // frames (hack!). 1.8777 + nsStyleChangeList changeList; 1.8778 + WalkFramesThroughPlaceholders(mPresContext, rootFrame, 1.8779 + ReframeImageBoxes, &changeList); 1.8780 + // Mark ourselves as not safe to flush while we're doing frame 1.8781 + // construction. 1.8782 + { 1.8783 + nsAutoScriptBlocker scriptBlocker; 1.8784 + ++mChangeNestCount; 1.8785 + RestyleManager* restyleManager = mPresContext->RestyleManager(); 1.8786 + restyleManager->ProcessRestyledFrames(changeList); 1.8787 + restyleManager->FlushOverflowChangedTracker(); 1.8788 + --mChangeNestCount; 1.8789 + } 1.8790 + } 1.8791 + } 1.8792 + return NS_OK; 1.8793 + } 1.8794 +#endif 1.8795 + 1.8796 + if (!nsCRT::strcmp(aTopic, "agent-sheet-added") && mStyleSet) { 1.8797 + AddAgentSheet(aSubject); 1.8798 + return NS_OK; 1.8799 + } 1.8800 + 1.8801 + if (!nsCRT::strcmp(aTopic, "user-sheet-added") && mStyleSet) { 1.8802 + AddUserSheet(aSubject); 1.8803 + return NS_OK; 1.8804 + } 1.8805 + 1.8806 + if (!nsCRT::strcmp(aTopic, "author-sheet-added") && mStyleSet) { 1.8807 + AddAuthorSheet(aSubject); 1.8808 + return NS_OK; 1.8809 + } 1.8810 + 1.8811 + if (!nsCRT::strcmp(aTopic, "agent-sheet-removed") && mStyleSet) { 1.8812 + RemoveSheet(nsStyleSet::eAgentSheet, aSubject); 1.8813 + return NS_OK; 1.8814 + } 1.8815 + 1.8816 + if (!nsCRT::strcmp(aTopic, "user-sheet-removed") && mStyleSet) { 1.8817 + RemoveSheet(nsStyleSet::eUserSheet, aSubject); 1.8818 + return NS_OK; 1.8819 + } 1.8820 + 1.8821 + if (!nsCRT::strcmp(aTopic, "author-sheet-removed") && mStyleSet) { 1.8822 + RemoveSheet(nsStyleSet::eDocSheet, aSubject); 1.8823 + return NS_OK; 1.8824 + } 1.8825 + 1.8826 + NS_WARNING("unrecognized topic in PresShell::Observe"); 1.8827 + return NS_ERROR_FAILURE; 1.8828 +} 1.8829 + 1.8830 +bool 1.8831 +nsIPresShell::AddRefreshObserverInternal(nsARefreshObserver* aObserver, 1.8832 + mozFlushType aFlushType) 1.8833 +{ 1.8834 + nsPresContext* presContext = GetPresContext(); 1.8835 + return presContext && 1.8836 + presContext->RefreshDriver()->AddRefreshObserver(aObserver, aFlushType); 1.8837 +} 1.8838 + 1.8839 +/* virtual */ bool 1.8840 +nsIPresShell::AddRefreshObserverExternal(nsARefreshObserver* aObserver, 1.8841 + mozFlushType aFlushType) 1.8842 +{ 1.8843 + return AddRefreshObserverInternal(aObserver, aFlushType); 1.8844 +} 1.8845 + 1.8846 +bool 1.8847 +nsIPresShell::RemoveRefreshObserverInternal(nsARefreshObserver* aObserver, 1.8848 + mozFlushType aFlushType) 1.8849 +{ 1.8850 + nsPresContext* presContext = GetPresContext(); 1.8851 + return presContext && 1.8852 + presContext->RefreshDriver()->RemoveRefreshObserver(aObserver, aFlushType); 1.8853 +} 1.8854 + 1.8855 +/* virtual */ bool 1.8856 +nsIPresShell::RemoveRefreshObserverExternal(nsARefreshObserver* aObserver, 1.8857 + mozFlushType aFlushType) 1.8858 +{ 1.8859 + return RemoveRefreshObserverInternal(aObserver, aFlushType); 1.8860 +} 1.8861 + 1.8862 +/* virtual */ bool 1.8863 +nsIPresShell::AddPostRefreshObserver(nsAPostRefreshObserver* aObserver) 1.8864 +{ 1.8865 + nsPresContext* presContext = GetPresContext(); 1.8866 + if (!presContext) { 1.8867 + return false; 1.8868 + } 1.8869 + presContext->RefreshDriver()->AddPostRefreshObserver(aObserver); 1.8870 + return true; 1.8871 +} 1.8872 + 1.8873 +/* virtual */ bool 1.8874 +nsIPresShell::RemovePostRefreshObserver(nsAPostRefreshObserver* aObserver) 1.8875 +{ 1.8876 + nsPresContext* presContext = GetPresContext(); 1.8877 + if (!presContext) { 1.8878 + return false; 1.8879 + } 1.8880 + presContext->RefreshDriver()->RemovePostRefreshObserver(aObserver); 1.8881 + return true; 1.8882 +} 1.8883 + 1.8884 +//------------------------------------------------------ 1.8885 +// End of protected and private methods on the PresShell 1.8886 +//------------------------------------------------------ 1.8887 + 1.8888 +//------------------------------------------------------------------ 1.8889 +//-- Delayed event Classes Impls 1.8890 +//------------------------------------------------------------------ 1.8891 + 1.8892 +PresShell::DelayedInputEvent::DelayedInputEvent() : 1.8893 + DelayedEvent(), 1.8894 + mEvent(nullptr) 1.8895 +{ 1.8896 +} 1.8897 + 1.8898 +PresShell::DelayedInputEvent::~DelayedInputEvent() 1.8899 +{ 1.8900 + delete mEvent; 1.8901 +} 1.8902 + 1.8903 +void 1.8904 +PresShell::DelayedInputEvent::Dispatch() 1.8905 +{ 1.8906 + if (!mEvent || !mEvent->widget) { 1.8907 + return; 1.8908 + } 1.8909 + nsCOMPtr<nsIWidget> widget = mEvent->widget; 1.8910 + nsEventStatus status; 1.8911 + widget->DispatchEvent(mEvent, status); 1.8912 +} 1.8913 + 1.8914 +PresShell::DelayedMouseEvent::DelayedMouseEvent(WidgetMouseEvent* aEvent) : 1.8915 + DelayedInputEvent() 1.8916 +{ 1.8917 + WidgetMouseEvent* mouseEvent = 1.8918 + new WidgetMouseEvent(aEvent->mFlags.mIsTrusted, 1.8919 + aEvent->message, 1.8920 + aEvent->widget, 1.8921 + aEvent->reason, 1.8922 + aEvent->context); 1.8923 + mouseEvent->AssignMouseEventData(*aEvent, false); 1.8924 + mEvent = mouseEvent; 1.8925 +} 1.8926 + 1.8927 +PresShell::DelayedKeyEvent::DelayedKeyEvent(WidgetKeyboardEvent* aEvent) : 1.8928 + DelayedInputEvent() 1.8929 +{ 1.8930 + WidgetKeyboardEvent* keyEvent = 1.8931 + new WidgetKeyboardEvent(aEvent->mFlags.mIsTrusted, 1.8932 + aEvent->message, 1.8933 + aEvent->widget); 1.8934 + keyEvent->AssignKeyEventData(*aEvent, false); 1.8935 + keyEvent->mFlags.mIsSynthesizedForTests = aEvent->mFlags.mIsSynthesizedForTests; 1.8936 + mEvent = keyEvent; 1.8937 +} 1.8938 + 1.8939 +// Start of DEBUG only code 1.8940 + 1.8941 +#ifdef DEBUG 1.8942 + 1.8943 +static void 1.8944 +LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg) 1.8945 +{ 1.8946 + nsAutoString n1, n2; 1.8947 + if (k1) { 1.8948 + k1->GetFrameName(n1); 1.8949 + } else { 1.8950 + n1.Assign(NS_LITERAL_STRING("(null)")); 1.8951 + } 1.8952 + 1.8953 + if (k2) { 1.8954 + k2->GetFrameName(n2); 1.8955 + } else { 1.8956 + n2.Assign(NS_LITERAL_STRING("(null)")); 1.8957 + } 1.8958 + 1.8959 + printf("verifyreflow: %s %p != %s %p %s\n", 1.8960 + NS_LossyConvertUTF16toASCII(n1).get(), (void*)k1, 1.8961 + NS_LossyConvertUTF16toASCII(n2).get(), (void*)k2, aMsg); 1.8962 +} 1.8963 + 1.8964 +static void 1.8965 +LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg, 1.8966 + const nsRect& r1, const nsRect& r2) 1.8967 +{ 1.8968 + printf("VerifyReflow Error:\n"); 1.8969 + nsAutoString name; 1.8970 + 1.8971 + if (k1) { 1.8972 + k1->GetFrameName(name); 1.8973 + printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1); 1.8974 + } 1.8975 + printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height); 1.8976 + 1.8977 + if (k2) { 1.8978 + k2->GetFrameName(name); 1.8979 + printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2); 1.8980 + } 1.8981 + printf("{%d, %d, %d, %d}\n %s\n", 1.8982 + r2.x, r2.y, r2.width, r2.height, aMsg); 1.8983 +} 1.8984 + 1.8985 +static void 1.8986 +LogVerifyMessage(nsIFrame* k1, nsIFrame* k2, const char* aMsg, 1.8987 + const nsIntRect& r1, const nsIntRect& r2) 1.8988 +{ 1.8989 + printf("VerifyReflow Error:\n"); 1.8990 + nsAutoString name; 1.8991 + 1.8992 + if (k1) { 1.8993 + k1->GetFrameName(name); 1.8994 + printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k1); 1.8995 + } 1.8996 + printf("{%d, %d, %d, %d} != \n", r1.x, r1.y, r1.width, r1.height); 1.8997 + 1.8998 + if (k2) { 1.8999 + k2->GetFrameName(name); 1.9000 + printf(" %s %p ", NS_LossyConvertUTF16toASCII(name).get(), (void*)k2); 1.9001 + } 1.9002 + printf("{%d, %d, %d, %d}\n %s\n", 1.9003 + r2.x, r2.y, r2.width, r2.height, aMsg); 1.9004 +} 1.9005 + 1.9006 +static bool 1.9007 +CompareTrees(nsPresContext* aFirstPresContext, nsIFrame* aFirstFrame, 1.9008 + nsPresContext* aSecondPresContext, nsIFrame* aSecondFrame) 1.9009 +{ 1.9010 + if (!aFirstPresContext || !aFirstFrame || !aSecondPresContext || !aSecondFrame) 1.9011 + return true; 1.9012 + // XXX Evil hack to reduce false positives; I can't seem to figure 1.9013 + // out how to flush scrollbar changes correctly 1.9014 + //if (aFirstFrame->GetType() == nsGkAtoms::scrollbarFrame) 1.9015 + // return true; 1.9016 + bool ok = true; 1.9017 + nsIFrame::ChildListIterator lists1(aFirstFrame); 1.9018 + nsIFrame::ChildListIterator lists2(aSecondFrame); 1.9019 + do { 1.9020 + const nsFrameList& kids1 = !lists1.IsDone() ? lists1.CurrentList() : nsFrameList(); 1.9021 + const nsFrameList& kids2 = !lists2.IsDone() ? lists2.CurrentList() : nsFrameList(); 1.9022 + int32_t l1 = kids1.GetLength(); 1.9023 + int32_t l2 = kids2.GetLength();; 1.9024 + if (l1 != l2) { 1.9025 + ok = false; 1.9026 + LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(), 1.9027 + "child counts don't match: "); 1.9028 + printf("%d != %d\n", l1, l2); 1.9029 + if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) { 1.9030 + break; 1.9031 + } 1.9032 + } 1.9033 + 1.9034 + nsIntRect r1, r2; 1.9035 + nsView* v1, *v2; 1.9036 + for (nsFrameList::Enumerator e1(kids1), e2(kids2); 1.9037 + ; 1.9038 + e1.Next(), e2.Next()) { 1.9039 + nsIFrame* k1 = e1.get(); 1.9040 + nsIFrame* k2 = e2.get(); 1.9041 + if (((nullptr == k1) && (nullptr != k2)) || 1.9042 + ((nullptr != k1) && (nullptr == k2))) { 1.9043 + ok = false; 1.9044 + LogVerifyMessage(k1, k2, "child lists are different\n"); 1.9045 + break; 1.9046 + } 1.9047 + else if (nullptr != k1) { 1.9048 + // Verify that the frames are the same size 1.9049 + if (!k1->GetRect().IsEqualInterior(k2->GetRect())) { 1.9050 + ok = false; 1.9051 + LogVerifyMessage(k1, k2, "(frame rects)", k1->GetRect(), k2->GetRect()); 1.9052 + } 1.9053 + 1.9054 + // Make sure either both have views or neither have views; if they 1.9055 + // do have views, make sure the views are the same size. If the 1.9056 + // views have widgets, make sure they both do or neither does. If 1.9057 + // they do, make sure the widgets are the same size. 1.9058 + v1 = k1->GetView(); 1.9059 + v2 = k2->GetView(); 1.9060 + if (((nullptr == v1) && (nullptr != v2)) || 1.9061 + ((nullptr != v1) && (nullptr == v2))) { 1.9062 + ok = false; 1.9063 + LogVerifyMessage(k1, k2, "child views are not matched\n"); 1.9064 + } 1.9065 + else if (nullptr != v1) { 1.9066 + if (!v1->GetBounds().IsEqualInterior(v2->GetBounds())) { 1.9067 + LogVerifyMessage(k1, k2, "(view rects)", v1->GetBounds(), v2->GetBounds()); 1.9068 + } 1.9069 + 1.9070 + nsIWidget* w1 = v1->GetWidget(); 1.9071 + nsIWidget* w2 = v2->GetWidget(); 1.9072 + if (((nullptr == w1) && (nullptr != w2)) || 1.9073 + ((nullptr != w1) && (nullptr == w2))) { 1.9074 + ok = false; 1.9075 + LogVerifyMessage(k1, k2, "child widgets are not matched\n"); 1.9076 + } 1.9077 + else if (nullptr != w1) { 1.9078 + w1->GetBounds(r1); 1.9079 + w2->GetBounds(r2); 1.9080 + if (!r1.IsEqualEdges(r2)) { 1.9081 + LogVerifyMessage(k1, k2, "(widget rects)", r1, r2); 1.9082 + } 1.9083 + } 1.9084 + } 1.9085 + if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) { 1.9086 + break; 1.9087 + } 1.9088 + 1.9089 + // XXX Should perhaps compare their float managers. 1.9090 + 1.9091 + // Compare the sub-trees too 1.9092 + if (!CompareTrees(aFirstPresContext, k1, aSecondPresContext, k2)) { 1.9093 + ok = false; 1.9094 + if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) { 1.9095 + break; 1.9096 + } 1.9097 + } 1.9098 + } 1.9099 + else { 1.9100 + break; 1.9101 + } 1.9102 + } 1.9103 + if (!ok && (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags))) { 1.9104 + break; 1.9105 + } 1.9106 + 1.9107 + lists1.Next(); 1.9108 + lists2.Next(); 1.9109 + if (lists1.IsDone() != lists2.IsDone() || 1.9110 + (!lists1.IsDone() && lists1.CurrentID() != lists2.CurrentID())) { 1.9111 + if (0 == (VERIFY_REFLOW_ALL & gVerifyReflowFlags)) { 1.9112 + ok = false; 1.9113 + } 1.9114 + LogVerifyMessage(kids1.FirstChild(), kids2.FirstChild(), 1.9115 + "child list names are not matched: "); 1.9116 + fprintf(stdout, "%s != %s\n", 1.9117 + !lists1.IsDone() ? mozilla::layout::ChildListName(lists1.CurrentID()) : "(null)", 1.9118 + !lists2.IsDone() ? mozilla::layout::ChildListName(lists2.CurrentID()) : "(null)"); 1.9119 + break; 1.9120 + } 1.9121 + } while (ok && !lists1.IsDone()); 1.9122 + 1.9123 + return ok; 1.9124 +} 1.9125 +#endif 1.9126 + 1.9127 +#if 0 1.9128 +static nsIFrame* 1.9129 +FindTopFrame(nsIFrame* aRoot) 1.9130 +{ 1.9131 + if (aRoot) { 1.9132 + nsIContent* content = aRoot->GetContent(); 1.9133 + if (content) { 1.9134 + nsIAtom* tag; 1.9135 + content->GetTag(tag); 1.9136 + if (nullptr != tag) { 1.9137 + NS_RELEASE(tag); 1.9138 + return aRoot; 1.9139 + } 1.9140 + } 1.9141 + 1.9142 + // Try one of the children 1.9143 + nsIFrame* kid = aRoot->GetFirstPrincipalChild(); 1.9144 + while (nullptr != kid) { 1.9145 + nsIFrame* result = FindTopFrame(kid); 1.9146 + if (nullptr != result) { 1.9147 + return result; 1.9148 + } 1.9149 + kid = kid->GetNextSibling(); 1.9150 + } 1.9151 + } 1.9152 + return nullptr; 1.9153 +} 1.9154 +#endif 1.9155 + 1.9156 + 1.9157 +#ifdef DEBUG 1.9158 + 1.9159 +nsStyleSet* 1.9160 +PresShell::CloneStyleSet(nsStyleSet* aSet) 1.9161 +{ 1.9162 + nsStyleSet *clone = new nsStyleSet(); 1.9163 + 1.9164 + int32_t i, n = aSet->SheetCount(nsStyleSet::eOverrideSheet); 1.9165 + for (i = 0; i < n; i++) { 1.9166 + nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eOverrideSheet, i); 1.9167 + if (ss) 1.9168 + clone->AppendStyleSheet(nsStyleSet::eOverrideSheet, ss); 1.9169 + } 1.9170 + 1.9171 + // The document expects to insert document stylesheets itself 1.9172 +#if 0 1.9173 + n = aSet->SheetCount(nsStyleSet::eDocSheet); 1.9174 + for (i = 0; i < n; i++) { 1.9175 + nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eDocSheet, i); 1.9176 + if (ss) 1.9177 + clone->AddDocStyleSheet(ss, mDocument); 1.9178 + } 1.9179 +#endif 1.9180 + 1.9181 + n = aSet->SheetCount(nsStyleSet::eUserSheet); 1.9182 + for (i = 0; i < n; i++) { 1.9183 + nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eUserSheet, i); 1.9184 + if (ss) 1.9185 + clone->AppendStyleSheet(nsStyleSet::eUserSheet, ss); 1.9186 + } 1.9187 + 1.9188 + n = aSet->SheetCount(nsStyleSet::eAgentSheet); 1.9189 + for (i = 0; i < n; i++) { 1.9190 + nsIStyleSheet* ss = aSet->StyleSheetAt(nsStyleSet::eAgentSheet, i); 1.9191 + if (ss) 1.9192 + clone->AppendStyleSheet(nsStyleSet::eAgentSheet, ss); 1.9193 + } 1.9194 + return clone; 1.9195 +} 1.9196 + 1.9197 +#ifdef DEBUG_Eli 1.9198 +static nsresult 1.9199 +DumpToPNG(nsIPresShell* shell, nsAString& name) { 1.9200 + int32_t width=1000, height=1000; 1.9201 + nsRect r(0, 0, shell->GetPresContext()->DevPixelsToAppUnits(width), 1.9202 + shell->GetPresContext()->DevPixelsToAppUnits(height)); 1.9203 + 1.9204 + nsRefPtr<gfxImageSurface> imgSurface = 1.9205 + new gfxImageSurface(gfxIntSize(width, height), 1.9206 + gfxImageFormat::ARGB32); 1.9207 + 1.9208 + nsRefPtr<gfxContext> imgContext = new gfxContext(imgSurface); 1.9209 + 1.9210 + nsRefPtr<gfxASurface> surface = 1.9211 + gfxPlatform::GetPlatform()-> 1.9212 + CreateOffscreenSurface(IntSize(width, height), 1.9213 + gfxASurface::ContentFromFormat(gfxImageFormat::ARGB32)); 1.9214 + NS_ENSURE_TRUE(surface, NS_ERROR_OUT_OF_MEMORY); 1.9215 + 1.9216 + nsRefPtr<gfxContext> context = new gfxContext(surface); 1.9217 + 1.9218 + shell->RenderDocument(r, 0, NS_RGB(255, 255, 0), context); 1.9219 + 1.9220 + imgContext->DrawSurface(surface, gfxSize(width, height)); 1.9221 + 1.9222 + nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png"); 1.9223 + NS_ENSURE_TRUE(encoder, NS_ERROR_FAILURE); 1.9224 + encoder->InitFromData(imgSurface->Data(), imgSurface->Stride() * height, 1.9225 + width, height, imgSurface->Stride(), 1.9226 + imgIEncoder::INPUT_FORMAT_HOSTARGB, EmptyString()); 1.9227 + 1.9228 + // XXX not sure if this is the right way to write to a file 1.9229 + nsCOMPtr<nsIFile> file = do_CreateInstance("@mozilla.org/file/local;1"); 1.9230 + NS_ENSURE_TRUE(file, NS_ERROR_FAILURE); 1.9231 + rv = file->InitWithPath(name); 1.9232 + NS_ENSURE_SUCCESS(rv, rv); 1.9233 + 1.9234 + uint64_t length64; 1.9235 + rv = encoder->Available(&length64); 1.9236 + NS_ENSURE_SUCCESS(rv, rv); 1.9237 + if (length64 > UINT32_MAX) 1.9238 + return NS_ERROR_FILE_TOO_BIG; 1.9239 + 1.9240 + uint32_t length = (uint32_t)length64; 1.9241 + 1.9242 + nsCOMPtr<nsIOutputStream> outputStream; 1.9243 + rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file); 1.9244 + NS_ENSURE_SUCCESS(rv, rv); 1.9245 + 1.9246 + nsCOMPtr<nsIOutputStream> bufferedOutputStream; 1.9247 + rv = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), 1.9248 + outputStream, length); 1.9249 + NS_ENSURE_SUCCESS(rv, rv); 1.9250 + 1.9251 + uint32_t numWritten; 1.9252 + rv = bufferedOutputStream->WriteFrom(encoder, length, &numWritten); 1.9253 + NS_ENSURE_SUCCESS(rv, rv); 1.9254 + 1.9255 + return NS_OK; 1.9256 +} 1.9257 +#endif 1.9258 + 1.9259 +// After an incremental reflow, we verify the correctness by doing a 1.9260 +// full reflow into a fresh frame tree. 1.9261 +bool 1.9262 +PresShell::VerifyIncrementalReflow() 1.9263 +{ 1.9264 + if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) { 1.9265 + printf("Building Verification Tree...\n"); 1.9266 + } 1.9267 + 1.9268 + // Create a presentation context to view the new frame tree 1.9269 + nsRefPtr<nsPresContext> cx = 1.9270 + new nsRootPresContext(mDocument, mPresContext->IsPaginated() ? 1.9271 + nsPresContext::eContext_PrintPreview : 1.9272 + nsPresContext::eContext_Galley); 1.9273 + NS_ENSURE_TRUE(cx, false); 1.9274 + 1.9275 + nsDeviceContext *dc = mPresContext->DeviceContext(); 1.9276 + nsresult rv = cx->Init(dc); 1.9277 + NS_ENSURE_SUCCESS(rv, false); 1.9278 + 1.9279 + // Get our scrolling preference 1.9280 + nsView* rootView = mViewManager->GetRootView(); 1.9281 + NS_ENSURE_TRUE(rootView->HasWidget(), false); 1.9282 + nsIWidget* parentWidget = rootView->GetWidget(); 1.9283 + 1.9284 + // Create a new view manager. 1.9285 + nsRefPtr<nsViewManager> vm = new nsViewManager(); 1.9286 + NS_ENSURE_TRUE(vm, false); 1.9287 + rv = vm->Init(dc); 1.9288 + NS_ENSURE_SUCCESS(rv, false); 1.9289 + 1.9290 + // Create a child window of the parent that is our "root view/window" 1.9291 + // Create a view 1.9292 + nsRect tbounds = mPresContext->GetVisibleArea(); 1.9293 + nsView* view = vm->CreateView(tbounds, nullptr); 1.9294 + NS_ENSURE_TRUE(view, false); 1.9295 + 1.9296 + //now create the widget for the view 1.9297 + rv = view->CreateWidgetForParent(parentWidget, nullptr, true); 1.9298 + NS_ENSURE_SUCCESS(rv, false); 1.9299 + 1.9300 + // Setup hierarchical relationship in view manager 1.9301 + vm->SetRootView(view); 1.9302 + 1.9303 + // Make the new presentation context the same size as our 1.9304 + // presentation context. 1.9305 + nsRect r = mPresContext->GetVisibleArea(); 1.9306 + cx->SetVisibleArea(r); 1.9307 + 1.9308 + // Create a new presentation shell to view the document. Use the 1.9309 + // exact same style information that this document has. 1.9310 + nsAutoPtr<nsStyleSet> newSet(CloneStyleSet(mStyleSet)); 1.9311 + nsCOMPtr<nsIPresShell> sh = mDocument->CreateShell(cx, vm, newSet); 1.9312 + NS_ENSURE_TRUE(sh, false); 1.9313 + newSet.forget(); 1.9314 + // Note that after we create the shell, we must make sure to destroy it 1.9315 + sh->SetVerifyReflowEnable(false); // turn off verify reflow while we're reflowing the test frame tree 1.9316 + vm->SetPresShell(sh); 1.9317 + { 1.9318 + nsAutoCauseReflowNotifier crNotifier(this); 1.9319 + sh->Initialize(r.width, r.height); 1.9320 + } 1.9321 + mDocument->BindingManager()->ProcessAttachedQueue(); 1.9322 + sh->FlushPendingNotifications(Flush_Layout); 1.9323 + sh->SetVerifyReflowEnable(true); // turn on verify reflow again now that we're done reflowing the test frame tree 1.9324 + // Force the non-primary presshell to unsuppress; it doesn't want to normally 1.9325 + // because it thinks it's hidden 1.9326 + ((PresShell*)sh.get())->mPaintingSuppressed = false; 1.9327 + if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) { 1.9328 + printf("Verification Tree built, comparing...\n"); 1.9329 + } 1.9330 + 1.9331 + // Now that the document has been reflowed, use its frame tree to 1.9332 + // compare against our frame tree. 1.9333 + nsIFrame* root1 = mFrameConstructor->GetRootFrame(); 1.9334 + nsIFrame* root2 = sh->GetRootFrame(); 1.9335 + bool ok = CompareTrees(mPresContext, root1, cx, root2); 1.9336 + if (!ok && (VERIFY_REFLOW_NOISY & gVerifyReflowFlags)) { 1.9337 + printf("Verify reflow failed, primary tree:\n"); 1.9338 + root1->List(stdout, 0); 1.9339 + printf("Verification tree:\n"); 1.9340 + root2->List(stdout, 0); 1.9341 + } 1.9342 + 1.9343 +#ifdef DEBUG_Eli 1.9344 + // Sample code for dumping page to png 1.9345 + // XXX Needs to be made more flexible 1.9346 + if (!ok) { 1.9347 + nsString stra; 1.9348 + static int num = 0; 1.9349 + stra.AppendLiteral("C:\\mozilla\\mozilla\\debug\\filea"); 1.9350 + stra.AppendInt(num); 1.9351 + stra.AppendLiteral(".png"); 1.9352 + DumpToPNG(sh, stra); 1.9353 + nsString strb; 1.9354 + strb.AppendLiteral("C:\\mozilla\\mozilla\\debug\\fileb"); 1.9355 + strb.AppendInt(num); 1.9356 + strb.AppendLiteral(".png"); 1.9357 + DumpToPNG(this, strb); 1.9358 + ++num; 1.9359 + } 1.9360 +#endif 1.9361 + 1.9362 + sh->EndObservingDocument(); 1.9363 + sh->Destroy(); 1.9364 + if (VERIFY_REFLOW_NOISY & gVerifyReflowFlags) { 1.9365 + printf("Finished Verifying Reflow...\n"); 1.9366 + } 1.9367 + 1.9368 + return ok; 1.9369 +} 1.9370 + 1.9371 +// Layout debugging hooks 1.9372 +void 1.9373 +PresShell::ListStyleContexts(nsIFrame *aRootFrame, FILE *out, int32_t aIndent) 1.9374 +{ 1.9375 + nsStyleContext *sc = aRootFrame->StyleContext(); 1.9376 + if (sc) 1.9377 + sc->List(out, aIndent); 1.9378 +} 1.9379 + 1.9380 +void 1.9381 +PresShell::ListStyleSheets(FILE *out, int32_t aIndent) 1.9382 +{ 1.9383 + int32_t sheetCount = mStyleSet->SheetCount(nsStyleSet::eDocSheet); 1.9384 + for (int32_t i = 0; i < sheetCount; ++i) { 1.9385 + mStyleSet->StyleSheetAt(nsStyleSet::eDocSheet, i)->List(out, aIndent); 1.9386 + fputs("\n", out); 1.9387 + } 1.9388 +} 1.9389 + 1.9390 +void 1.9391 +PresShell::VerifyStyleTree() 1.9392 +{ 1.9393 + VERIFY_STYLE_TREE; 1.9394 +} 1.9395 +#endif 1.9396 + 1.9397 +//============================================================= 1.9398 +//============================================================= 1.9399 +//-- Debug Reflow Counts 1.9400 +//============================================================= 1.9401 +//============================================================= 1.9402 +#ifdef MOZ_REFLOW_PERF 1.9403 +//------------------------------------------------------------- 1.9404 +void 1.9405 +PresShell::DumpReflows() 1.9406 +{ 1.9407 + if (mReflowCountMgr) { 1.9408 + nsAutoCString uriStr; 1.9409 + if (mDocument) { 1.9410 + nsIURI *uri = mDocument->GetDocumentURI(); 1.9411 + if (uri) { 1.9412 + uri->GetPath(uriStr); 1.9413 + } 1.9414 + } 1.9415 + mReflowCountMgr->DisplayTotals(uriStr.get()); 1.9416 + mReflowCountMgr->DisplayHTMLTotals(uriStr.get()); 1.9417 + mReflowCountMgr->DisplayDiffsInTotals("Differences"); 1.9418 + } 1.9419 +} 1.9420 + 1.9421 +//------------------------------------------------------------- 1.9422 +void 1.9423 +PresShell::CountReflows(const char * aName, nsIFrame * aFrame) 1.9424 +{ 1.9425 + if (mReflowCountMgr) { 1.9426 + mReflowCountMgr->Add(aName, aFrame); 1.9427 + } 1.9428 +} 1.9429 + 1.9430 +//------------------------------------------------------------- 1.9431 +void 1.9432 +PresShell::PaintCount(const char * aName, 1.9433 + nsRenderingContext* aRenderingContext, 1.9434 + nsPresContext* aPresContext, 1.9435 + nsIFrame * aFrame, 1.9436 + const nsPoint& aOffset, 1.9437 + uint32_t aColor) 1.9438 +{ 1.9439 + if (mReflowCountMgr) { 1.9440 + mReflowCountMgr->PaintCount(aName, aRenderingContext, aPresContext, 1.9441 + aFrame, aOffset, aColor); 1.9442 + } 1.9443 +} 1.9444 + 1.9445 +//------------------------------------------------------------- 1.9446 +void 1.9447 +PresShell::SetPaintFrameCount(bool aPaintFrameCounts) 1.9448 +{ 1.9449 + if (mReflowCountMgr) { 1.9450 + mReflowCountMgr->SetPaintFrameCounts(aPaintFrameCounts); 1.9451 + } 1.9452 +} 1.9453 + 1.9454 +bool 1.9455 +PresShell::IsPaintingFrameCounts() 1.9456 +{ 1.9457 + if (mReflowCountMgr) 1.9458 + return mReflowCountMgr->IsPaintingFrameCounts(); 1.9459 + return false; 1.9460 +} 1.9461 + 1.9462 +//------------------------------------------------------------------ 1.9463 +//-- Reflow Counter Classes Impls 1.9464 +//------------------------------------------------------------------ 1.9465 + 1.9466 +//------------------------------------------------------------------ 1.9467 +ReflowCounter::ReflowCounter(ReflowCountMgr * aMgr) : 1.9468 + mMgr(aMgr) 1.9469 +{ 1.9470 + ClearTotals(); 1.9471 + SetTotalsCache(); 1.9472 +} 1.9473 + 1.9474 +//------------------------------------------------------------------ 1.9475 +ReflowCounter::~ReflowCounter() 1.9476 +{ 1.9477 + 1.9478 +} 1.9479 + 1.9480 +//------------------------------------------------------------------ 1.9481 +void ReflowCounter::ClearTotals() 1.9482 +{ 1.9483 + mTotal = 0; 1.9484 +} 1.9485 + 1.9486 +//------------------------------------------------------------------ 1.9487 +void ReflowCounter::SetTotalsCache() 1.9488 +{ 1.9489 + mCacheTotal = mTotal; 1.9490 +} 1.9491 + 1.9492 +//------------------------------------------------------------------ 1.9493 +void ReflowCounter::CalcDiffInTotals() 1.9494 +{ 1.9495 + mCacheTotal = mTotal - mCacheTotal; 1.9496 +} 1.9497 + 1.9498 +//------------------------------------------------------------------ 1.9499 +void ReflowCounter::DisplayTotals(const char * aStr) 1.9500 +{ 1.9501 + DisplayTotals(mTotal, aStr?aStr:"Totals"); 1.9502 +} 1.9503 + 1.9504 +//------------------------------------------------------------------ 1.9505 +void ReflowCounter::DisplayDiffTotals(const char * aStr) 1.9506 +{ 1.9507 + DisplayTotals(mCacheTotal, aStr?aStr:"Diff Totals"); 1.9508 +} 1.9509 + 1.9510 +//------------------------------------------------------------------ 1.9511 +void ReflowCounter::DisplayHTMLTotals(const char * aStr) 1.9512 +{ 1.9513 + DisplayHTMLTotals(mTotal, aStr?aStr:"Totals"); 1.9514 +} 1.9515 + 1.9516 +//------------------------------------------------------------------ 1.9517 +void ReflowCounter::DisplayTotals(uint32_t aTotal, const char * aTitle) 1.9518 +{ 1.9519 + // figure total 1.9520 + if (aTotal == 0) { 1.9521 + return; 1.9522 + } 1.9523 + ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr); 1.9524 + 1.9525 + printf("%25s\t", aTitle); 1.9526 + printf("%d\t", aTotal); 1.9527 + if (gTots != this && aTotal > 0) { 1.9528 + gTots->Add(aTotal); 1.9529 + } 1.9530 +} 1.9531 + 1.9532 +//------------------------------------------------------------------ 1.9533 +void ReflowCounter::DisplayHTMLTotals(uint32_t aTotal, const char * aTitle) 1.9534 +{ 1.9535 + if (aTotal == 0) { 1.9536 + return; 1.9537 + } 1.9538 + 1.9539 + ReflowCounter * gTots = (ReflowCounter *)mMgr->LookUp(kGrandTotalsStr); 1.9540 + FILE * fd = mMgr->GetOutFile(); 1.9541 + if (!fd) { 1.9542 + return; 1.9543 + } 1.9544 + 1.9545 + fprintf(fd, "<tr><td><center>%s</center></td>", aTitle); 1.9546 + fprintf(fd, "<td><center>%d</center></td></tr>\n", aTotal); 1.9547 + 1.9548 + if (gTots != this && aTotal > 0) { 1.9549 + gTots->Add(aTotal); 1.9550 + } 1.9551 +} 1.9552 + 1.9553 +//------------------------------------------------------------------ 1.9554 +//-- ReflowCountMgr 1.9555 +//------------------------------------------------------------------ 1.9556 + 1.9557 +#define KEY_BUF_SIZE_FOR_PTR 24 // adequate char[] buffer to sprintf a pointer 1.9558 + 1.9559 +ReflowCountMgr::ReflowCountMgr() 1.9560 +{ 1.9561 + mCounts = PL_NewHashTable(10, PL_HashString, PL_CompareStrings, 1.9562 + PL_CompareValues, nullptr, nullptr); 1.9563 + mIndiFrameCounts = PL_NewHashTable(10, PL_HashString, PL_CompareStrings, 1.9564 + PL_CompareValues, nullptr, nullptr); 1.9565 + mCycledOnce = false; 1.9566 + mDumpFrameCounts = false; 1.9567 + mDumpFrameByFrameCounts = false; 1.9568 + mPaintFrameByFrameCounts = false; 1.9569 +} 1.9570 + 1.9571 +//------------------------------------------------------------------ 1.9572 +ReflowCountMgr::~ReflowCountMgr() 1.9573 +{ 1.9574 + CleanUp(); 1.9575 +} 1.9576 + 1.9577 +//------------------------------------------------------------------ 1.9578 +ReflowCounter * ReflowCountMgr::LookUp(const char * aName) 1.9579 +{ 1.9580 + if (nullptr != mCounts) { 1.9581 + ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName); 1.9582 + return counter; 1.9583 + } 1.9584 + return nullptr; 1.9585 + 1.9586 +} 1.9587 + 1.9588 +//------------------------------------------------------------------ 1.9589 +void ReflowCountMgr::Add(const char * aName, nsIFrame * aFrame) 1.9590 +{ 1.9591 + NS_ASSERTION(aName != nullptr, "Name shouldn't be null!"); 1.9592 + 1.9593 + if (mDumpFrameCounts && nullptr != mCounts) { 1.9594 + ReflowCounter * counter = (ReflowCounter *)PL_HashTableLookup(mCounts, aName); 1.9595 + if (counter == nullptr) { 1.9596 + counter = new ReflowCounter(this); 1.9597 + char * name = NS_strdup(aName); 1.9598 + NS_ASSERTION(name != nullptr, "null ptr"); 1.9599 + PL_HashTableAdd(mCounts, name, counter); 1.9600 + } 1.9601 + counter->Add(); 1.9602 + } 1.9603 + 1.9604 + if ((mDumpFrameByFrameCounts || mPaintFrameByFrameCounts) && 1.9605 + nullptr != mIndiFrameCounts && 1.9606 + aFrame != nullptr) { 1.9607 + char key[KEY_BUF_SIZE_FOR_PTR]; 1.9608 + sprintf(key, "%p", (void*)aFrame); 1.9609 + IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key); 1.9610 + if (counter == nullptr) { 1.9611 + counter = new IndiReflowCounter(this); 1.9612 + counter->mFrame = aFrame; 1.9613 + counter->mName.AssignASCII(aName); 1.9614 + PL_HashTableAdd(mIndiFrameCounts, NS_strdup(key), counter); 1.9615 + } 1.9616 + // this eliminates extra counts from super classes 1.9617 + if (counter != nullptr && counter->mName.EqualsASCII(aName)) { 1.9618 + counter->mCount++; 1.9619 + counter->mCounter.Add(1); 1.9620 + } 1.9621 + } 1.9622 +} 1.9623 + 1.9624 +//------------------------------------------------------------------ 1.9625 +void ReflowCountMgr::PaintCount(const char* aName, 1.9626 + nsRenderingContext* aRenderingContext, 1.9627 + nsPresContext* aPresContext, 1.9628 + nsIFrame* aFrame, 1.9629 + const nsPoint& aOffset, 1.9630 + uint32_t aColor) 1.9631 +{ 1.9632 + if (mPaintFrameByFrameCounts && 1.9633 + nullptr != mIndiFrameCounts && 1.9634 + aFrame != nullptr) { 1.9635 + char key[KEY_BUF_SIZE_FOR_PTR]; 1.9636 + sprintf(key, "%p", (void*)aFrame); 1.9637 + IndiReflowCounter * counter = 1.9638 + (IndiReflowCounter *)PL_HashTableLookup(mIndiFrameCounts, key); 1.9639 + if (counter != nullptr && counter->mName.EqualsASCII(aName)) { 1.9640 + aRenderingContext->PushState(); 1.9641 + aRenderingContext->Translate(aOffset); 1.9642 + nsFont font("Times", NS_FONT_STYLE_NORMAL, NS_FONT_VARIANT_NORMAL, 1.9643 + NS_FONT_WEIGHT_NORMAL, NS_FONT_STRETCH_NORMAL, 0, 1.9644 + nsPresContext::CSSPixelsToAppUnits(11)); 1.9645 + 1.9646 + nsRefPtr<nsFontMetrics> fm; 1.9647 + aPresContext->DeviceContext()->GetMetricsFor(font, 1.9648 + // We have one frame, therefore we must have a root... 1.9649 + aPresContext->GetPresShell()->GetRootFrame()-> 1.9650 + StyleFont()->mLanguage, 1.9651 + aPresContext->GetUserFontSet(), 1.9652 + aPresContext->GetTextPerfMetrics(), 1.9653 + *getter_AddRefs(fm)); 1.9654 + 1.9655 + aRenderingContext->SetFont(fm); 1.9656 + char buf[16]; 1.9657 + sprintf(buf, "%d", counter->mCount); 1.9658 + nscoord x = 0, y = fm->MaxAscent(); 1.9659 + nscoord width, height = fm->MaxHeight(); 1.9660 + aRenderingContext->SetTextRunRTL(false); 1.9661 + width = aRenderingContext->GetWidth(buf); 1.9662 + 1.9663 + uint32_t color; 1.9664 + uint32_t color2; 1.9665 + if (aColor != 0) { 1.9666 + color = aColor; 1.9667 + color2 = NS_RGB(0,0,0); 1.9668 + } else { 1.9669 + uint8_t rc = 0, gc = 0, bc = 0; 1.9670 + if (counter->mCount < 5) { 1.9671 + rc = 255; 1.9672 + gc = 255; 1.9673 + } else if ( counter->mCount < 11) { 1.9674 + gc = 255; 1.9675 + } else { 1.9676 + rc = 255; 1.9677 + } 1.9678 + color = NS_RGB(rc,gc,bc); 1.9679 + color2 = NS_RGB(rc/2,gc/2,bc/2); 1.9680 + } 1.9681 + 1.9682 + nsRect rect(0,0, width+15, height+15); 1.9683 + aRenderingContext->SetColor(NS_RGB(0,0,0)); 1.9684 + aRenderingContext->FillRect(rect); 1.9685 + aRenderingContext->SetColor(color2); 1.9686 + aRenderingContext->DrawString(buf, strlen(buf), x+15,y+15); 1.9687 + aRenderingContext->SetColor(color); 1.9688 + aRenderingContext->DrawString(buf, strlen(buf), x,y); 1.9689 + 1.9690 + aRenderingContext->PopState(); 1.9691 + } 1.9692 + } 1.9693 +} 1.9694 + 1.9695 +//------------------------------------------------------------------ 1.9696 +int ReflowCountMgr::RemoveItems(PLHashEntry *he, int i, void *arg) 1.9697 +{ 1.9698 + char *str = (char *)he->key; 1.9699 + ReflowCounter * counter = (ReflowCounter *)he->value; 1.9700 + delete counter; 1.9701 + NS_Free(str); 1.9702 + 1.9703 + return HT_ENUMERATE_REMOVE; 1.9704 +} 1.9705 + 1.9706 +//------------------------------------------------------------------ 1.9707 +int ReflowCountMgr::RemoveIndiItems(PLHashEntry *he, int i, void *arg) 1.9708 +{ 1.9709 + char *str = (char *)he->key; 1.9710 + IndiReflowCounter * counter = (IndiReflowCounter *)he->value; 1.9711 + delete counter; 1.9712 + NS_Free(str); 1.9713 + 1.9714 + return HT_ENUMERATE_REMOVE; 1.9715 +} 1.9716 + 1.9717 +//------------------------------------------------------------------ 1.9718 +void ReflowCountMgr::CleanUp() 1.9719 +{ 1.9720 + if (nullptr != mCounts) { 1.9721 + PL_HashTableEnumerateEntries(mCounts, RemoveItems, nullptr); 1.9722 + PL_HashTableDestroy(mCounts); 1.9723 + mCounts = nullptr; 1.9724 + } 1.9725 + 1.9726 + if (nullptr != mIndiFrameCounts) { 1.9727 + PL_HashTableEnumerateEntries(mIndiFrameCounts, RemoveIndiItems, nullptr); 1.9728 + PL_HashTableDestroy(mIndiFrameCounts); 1.9729 + mIndiFrameCounts = nullptr; 1.9730 + } 1.9731 +} 1.9732 + 1.9733 +//------------------------------------------------------------------ 1.9734 +int ReflowCountMgr::DoSingleTotal(PLHashEntry *he, int i, void *arg) 1.9735 +{ 1.9736 + char *str = (char *)he->key; 1.9737 + ReflowCounter * counter = (ReflowCounter *)he->value; 1.9738 + 1.9739 + counter->DisplayTotals(str); 1.9740 + 1.9741 + return HT_ENUMERATE_NEXT; 1.9742 +} 1.9743 + 1.9744 +//------------------------------------------------------------------ 1.9745 +void ReflowCountMgr::DoGrandTotals() 1.9746 +{ 1.9747 + if (nullptr != mCounts) { 1.9748 + ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr); 1.9749 + if (gTots == nullptr) { 1.9750 + gTots = new ReflowCounter(this); 1.9751 + PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots); 1.9752 + } else { 1.9753 + gTots->ClearTotals(); 1.9754 + } 1.9755 + 1.9756 + printf("\t\t\t\tTotal\n"); 1.9757 + for (uint32_t i=0;i<78;i++) { 1.9758 + printf("-"); 1.9759 + } 1.9760 + printf("\n"); 1.9761 + PL_HashTableEnumerateEntries(mCounts, DoSingleTotal, this); 1.9762 + } 1.9763 +} 1.9764 + 1.9765 +static void RecurseIndiTotals(nsPresContext* aPresContext, 1.9766 + PLHashTable * aHT, 1.9767 + nsIFrame * aParentFrame, 1.9768 + int32_t aLevel) 1.9769 +{ 1.9770 + if (aParentFrame == nullptr) { 1.9771 + return; 1.9772 + } 1.9773 + 1.9774 + char key[KEY_BUF_SIZE_FOR_PTR]; 1.9775 + sprintf(key, "%p", (void*)aParentFrame); 1.9776 + IndiReflowCounter * counter = (IndiReflowCounter *)PL_HashTableLookup(aHT, key); 1.9777 + if (counter) { 1.9778 + counter->mHasBeenOutput = true; 1.9779 + char * name = ToNewCString(counter->mName); 1.9780 + for (int32_t i=0;i<aLevel;i++) printf(" "); 1.9781 + printf("%s - %p [%d][", name, (void*)aParentFrame, counter->mCount); 1.9782 + printf("%d", counter->mCounter.GetTotal()); 1.9783 + printf("]\n"); 1.9784 + nsMemory::Free(name); 1.9785 + } 1.9786 + 1.9787 + nsIFrame* child = aParentFrame->GetFirstPrincipalChild(); 1.9788 + while (child) { 1.9789 + RecurseIndiTotals(aPresContext, aHT, child, aLevel+1); 1.9790 + child = child->GetNextSibling(); 1.9791 + } 1.9792 + 1.9793 +} 1.9794 + 1.9795 +//------------------------------------------------------------------ 1.9796 +int ReflowCountMgr::DoSingleIndi(PLHashEntry *he, int i, void *arg) 1.9797 +{ 1.9798 + IndiReflowCounter * counter = (IndiReflowCounter *)he->value; 1.9799 + if (counter && !counter->mHasBeenOutput) { 1.9800 + char * name = ToNewCString(counter->mName); 1.9801 + printf("%s - %p [%d][", name, (void*)counter->mFrame, counter->mCount); 1.9802 + printf("%d", counter->mCounter.GetTotal()); 1.9803 + printf("]\n"); 1.9804 + nsMemory::Free(name); 1.9805 + } 1.9806 + return HT_ENUMERATE_NEXT; 1.9807 +} 1.9808 + 1.9809 +//------------------------------------------------------------------ 1.9810 +void ReflowCountMgr::DoIndiTotalsTree() 1.9811 +{ 1.9812 + if (nullptr != mCounts) { 1.9813 + printf("\n------------------------------------------------\n"); 1.9814 + printf("-- Individual Frame Counts\n"); 1.9815 + printf("------------------------------------------------\n"); 1.9816 + 1.9817 + if (mPresShell) { 1.9818 + nsIFrame * rootFrame = mPresShell->FrameManager()->GetRootFrame(); 1.9819 + RecurseIndiTotals(mPresContext, mIndiFrameCounts, rootFrame, 0); 1.9820 + printf("------------------------------------------------\n"); 1.9821 + printf("-- Individual Counts of Frames not in Root Tree\n"); 1.9822 + printf("------------------------------------------------\n"); 1.9823 + PL_HashTableEnumerateEntries(mIndiFrameCounts, DoSingleIndi, this); 1.9824 + } 1.9825 + } 1.9826 +} 1.9827 + 1.9828 +//------------------------------------------------------------------ 1.9829 +int ReflowCountMgr::DoSingleHTMLTotal(PLHashEntry *he, int i, void *arg) 1.9830 +{ 1.9831 + char *str = (char *)he->key; 1.9832 + ReflowCounter * counter = (ReflowCounter *)he->value; 1.9833 + 1.9834 + counter->DisplayHTMLTotals(str); 1.9835 + 1.9836 + return HT_ENUMERATE_NEXT; 1.9837 +} 1.9838 + 1.9839 +//------------------------------------------------------------------ 1.9840 +void ReflowCountMgr::DoGrandHTMLTotals() 1.9841 +{ 1.9842 + if (nullptr != mCounts) { 1.9843 + ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr); 1.9844 + if (gTots == nullptr) { 1.9845 + gTots = new ReflowCounter(this); 1.9846 + PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots); 1.9847 + } else { 1.9848 + gTots->ClearTotals(); 1.9849 + } 1.9850 + 1.9851 + static const char * title[] = {"Class", "Reflows"}; 1.9852 + fprintf(mFD, "<tr>"); 1.9853 + for (uint32_t i=0; i < ArrayLength(title); i++) { 1.9854 + fprintf(mFD, "<td><center><b>%s<b></center></td>", title[i]); 1.9855 + } 1.9856 + fprintf(mFD, "</tr>\n"); 1.9857 + PL_HashTableEnumerateEntries(mCounts, DoSingleHTMLTotal, this); 1.9858 + } 1.9859 +} 1.9860 + 1.9861 +//------------------------------------ 1.9862 +void ReflowCountMgr::DisplayTotals(const char * aStr) 1.9863 +{ 1.9864 +#ifdef DEBUG_rods 1.9865 + printf("%s\n", aStr?aStr:"No name"); 1.9866 +#endif 1.9867 + if (mDumpFrameCounts) { 1.9868 + DoGrandTotals(); 1.9869 + } 1.9870 + if (mDumpFrameByFrameCounts) { 1.9871 + DoIndiTotalsTree(); 1.9872 + } 1.9873 + 1.9874 +} 1.9875 +//------------------------------------ 1.9876 +void ReflowCountMgr::DisplayHTMLTotals(const char * aStr) 1.9877 +{ 1.9878 +#ifdef WIN32x // XXX NOT XP! 1.9879 + char name[1024]; 1.9880 + 1.9881 + char * sptr = strrchr(aStr, '/'); 1.9882 + if (sptr) { 1.9883 + sptr++; 1.9884 + strcpy(name, sptr); 1.9885 + char * eptr = strrchr(name, '.'); 1.9886 + if (eptr) { 1.9887 + *eptr = 0; 1.9888 + } 1.9889 + strcat(name, "_stats.html"); 1.9890 + } 1.9891 + mFD = fopen(name, "w"); 1.9892 + if (mFD) { 1.9893 + fprintf(mFD, "<html><head><title>Reflow Stats</title></head><body>\n"); 1.9894 + const char * title = aStr?aStr:"No name"; 1.9895 + fprintf(mFD, "<center><b>%s</b><br><table border=1 style=\"background-color:#e0e0e0\">", title); 1.9896 + DoGrandHTMLTotals(); 1.9897 + fprintf(mFD, "</center></table>\n"); 1.9898 + fprintf(mFD, "</body></html>\n"); 1.9899 + fclose(mFD); 1.9900 + mFD = nullptr; 1.9901 + } 1.9902 +#endif // not XP! 1.9903 +} 1.9904 + 1.9905 +//------------------------------------------------------------------ 1.9906 +int ReflowCountMgr::DoClearTotals(PLHashEntry *he, int i, void *arg) 1.9907 +{ 1.9908 + ReflowCounter * counter = (ReflowCounter *)he->value; 1.9909 + counter->ClearTotals(); 1.9910 + 1.9911 + return HT_ENUMERATE_NEXT; 1.9912 +} 1.9913 + 1.9914 +//------------------------------------------------------------------ 1.9915 +void ReflowCountMgr::ClearTotals() 1.9916 +{ 1.9917 + PL_HashTableEnumerateEntries(mCounts, DoClearTotals, this); 1.9918 +} 1.9919 + 1.9920 +//------------------------------------------------------------------ 1.9921 +void ReflowCountMgr::ClearGrandTotals() 1.9922 +{ 1.9923 + if (nullptr != mCounts) { 1.9924 + ReflowCounter * gTots = (ReflowCounter *)PL_HashTableLookup(mCounts, kGrandTotalsStr); 1.9925 + if (gTots == nullptr) { 1.9926 + gTots = new ReflowCounter(this); 1.9927 + PL_HashTableAdd(mCounts, NS_strdup(kGrandTotalsStr), gTots); 1.9928 + } else { 1.9929 + gTots->ClearTotals(); 1.9930 + gTots->SetTotalsCache(); 1.9931 + } 1.9932 + } 1.9933 +} 1.9934 + 1.9935 +//------------------------------------------------------------------ 1.9936 +int ReflowCountMgr::DoDisplayDiffTotals(PLHashEntry *he, int i, void *arg) 1.9937 +{ 1.9938 + bool cycledOnce = (arg != 0); 1.9939 + 1.9940 + char *str = (char *)he->key; 1.9941 + ReflowCounter * counter = (ReflowCounter *)he->value; 1.9942 + 1.9943 + if (cycledOnce) { 1.9944 + counter->CalcDiffInTotals(); 1.9945 + counter->DisplayDiffTotals(str); 1.9946 + } 1.9947 + counter->SetTotalsCache(); 1.9948 + 1.9949 + return HT_ENUMERATE_NEXT; 1.9950 +} 1.9951 + 1.9952 +//------------------------------------------------------------------ 1.9953 +void ReflowCountMgr::DisplayDiffsInTotals(const char * aStr) 1.9954 +{ 1.9955 + if (mCycledOnce) { 1.9956 + printf("Differences\n"); 1.9957 + for (int32_t i=0;i<78;i++) { 1.9958 + printf("-"); 1.9959 + } 1.9960 + printf("\n"); 1.9961 + ClearGrandTotals(); 1.9962 + } 1.9963 + PL_HashTableEnumerateEntries(mCounts, DoDisplayDiffTotals, (void *)mCycledOnce); 1.9964 + 1.9965 + mCycledOnce = true; 1.9966 +} 1.9967 + 1.9968 +#endif // MOZ_REFLOW_PERF 1.9969 + 1.9970 +// make a color string like #RRGGBB 1.9971 +void ColorToString(nscolor aColor, nsAutoString &aString) 1.9972 +{ 1.9973 + char buf[8]; 1.9974 + 1.9975 + PR_snprintf(buf, sizeof(buf), "#%02x%02x%02x", 1.9976 + NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor)); 1.9977 + CopyASCIItoUTF16(buf, aString); 1.9978 +} 1.9979 + 1.9980 +nsIFrame* nsIPresShell::GetAbsoluteContainingBlock(nsIFrame *aFrame) 1.9981 +{ 1.9982 + return FrameConstructor()->GetAbsoluteContainingBlock(aFrame, 1.9983 + nsCSSFrameConstructor::ABS_POS); 1.9984 +} 1.9985 + 1.9986 +#ifdef ACCESSIBILITY 1.9987 +bool 1.9988 +nsIPresShell::IsAccessibilityActive() 1.9989 +{ 1.9990 + return GetAccService() != nullptr; 1.9991 +} 1.9992 + 1.9993 +nsAccessibilityService* 1.9994 +nsIPresShell::AccService() 1.9995 +{ 1.9996 + return GetAccService(); 1.9997 +} 1.9998 +#endif 1.9999 + 1.10000 +void nsIPresShell::InitializeStatics() 1.10001 +{ 1.10002 + NS_ASSERTION(!gCaptureTouchList, "InitializeStatics called multiple times!"); 1.10003 + gCaptureTouchList = new nsRefPtrHashtable<nsUint32HashKey, dom::Touch>; 1.10004 + gPointerCaptureList = new nsRefPtrHashtable<nsUint32HashKey, nsIContent>; 1.10005 + gActivePointersIds = new nsClassHashtable<nsUint32HashKey, PointerInfo>; 1.10006 +} 1.10007 + 1.10008 +void nsIPresShell::ReleaseStatics() 1.10009 +{ 1.10010 + NS_ASSERTION(gCaptureTouchList, "ReleaseStatics called without Initialize!"); 1.10011 + delete gCaptureTouchList; 1.10012 + gCaptureTouchList = nullptr; 1.10013 + delete gPointerCaptureList; 1.10014 + gPointerCaptureList = nullptr; 1.10015 + delete gActivePointersIds; 1.10016 + gActivePointersIds = nullptr; 1.10017 +} 1.10018 + 1.10019 +// Asks our docshell whether we're active. 1.10020 +void PresShell::QueryIsActive() 1.10021 +{ 1.10022 + nsCOMPtr<nsISupports> container = mPresContext->GetContainerWeak(); 1.10023 + if (mDocument) { 1.10024 + nsIDocument* displayDoc = mDocument->GetDisplayDocument(); 1.10025 + if (displayDoc) { 1.10026 + // Ok, we're an external resource document -- we need to use our display 1.10027 + // document's docshell to determine "IsActive" status, since we lack 1.10028 + // a container. 1.10029 + NS_ABORT_IF_FALSE(!container, 1.10030 + "external resource doc shouldn't have " 1.10031 + "its own container"); 1.10032 + 1.10033 + nsIPresShell* displayPresShell = displayDoc->GetShell(); 1.10034 + if (displayPresShell) { 1.10035 + container = displayPresShell->GetPresContext()->GetContainerWeak(); 1.10036 + } 1.10037 + } 1.10038 + } 1.10039 + 1.10040 + nsCOMPtr<nsIDocShell> docshell(do_QueryInterface(container)); 1.10041 + if (docshell) { 1.10042 + bool isActive; 1.10043 + nsresult rv = docshell->GetIsActive(&isActive); 1.10044 + if (NS_SUCCEEDED(rv)) 1.10045 + SetIsActive(isActive); 1.10046 + } 1.10047 +} 1.10048 + 1.10049 +// Helper for propagating mIsActive changes to external resources 1.10050 +static bool 1.10051 +SetExternalResourceIsActive(nsIDocument* aDocument, void* aClosure) 1.10052 +{ 1.10053 + nsIPresShell* shell = aDocument->GetShell(); 1.10054 + if (shell) { 1.10055 + shell->SetIsActive(*static_cast<bool*>(aClosure)); 1.10056 + } 1.10057 + return true; 1.10058 +} 1.10059 + 1.10060 +static void 1.10061 +SetPluginIsActive(nsIContent* aContent, void* aClosure) 1.10062 +{ 1.10063 + nsIFrame *frame = aContent->GetPrimaryFrame(); 1.10064 + nsIObjectFrame *objectFrame = do_QueryFrame(frame); 1.10065 + if (objectFrame) { 1.10066 + objectFrame->SetIsDocumentActive(*static_cast<bool*>(aClosure)); 1.10067 + } 1.10068 +} 1.10069 + 1.10070 +nsresult 1.10071 +PresShell::SetIsActive(bool aIsActive) 1.10072 +{ 1.10073 + NS_PRECONDITION(mDocument, "should only be called with a document"); 1.10074 + 1.10075 + mIsActive = aIsActive; 1.10076 + nsPresContext* presContext = GetPresContext(); 1.10077 + if (presContext && 1.10078 + presContext->RefreshDriver()->PresContext() == presContext) { 1.10079 + presContext->RefreshDriver()->SetThrottled(!mIsActive); 1.10080 + } 1.10081 + 1.10082 + // Propagate state-change to my resource documents' PresShells 1.10083 + mDocument->EnumerateExternalResources(SetExternalResourceIsActive, 1.10084 + &aIsActive); 1.10085 + mDocument->EnumerateFreezableElements(SetPluginIsActive, 1.10086 + &aIsActive); 1.10087 + nsresult rv = UpdateImageLockingState(); 1.10088 +#ifdef ACCESSIBILITY 1.10089 + if (aIsActive) { 1.10090 + nsAccessibilityService* accService = AccService(); 1.10091 + if (accService) { 1.10092 + accService->PresShellActivated(this); 1.10093 + } 1.10094 + } 1.10095 +#endif 1.10096 + 1.10097 + // We have this odd special case here because remote content behaves 1.10098 + // differently from same-process content when "hidden". In 1.10099 + // desktop-type "browser UIs", hidden "tabs" have documents that are 1.10100 + // part of the chrome tree. When the tabs are hidden, their content 1.10101 + // is no longer part of the visible document tree, and the layers 1.10102 + // for the content are naturally released. 1.10103 + // 1.10104 + // Remote content is its own top-level tree in its subprocess. When 1.10105 + // it's "hidden", there's no transaction in which the document 1.10106 + // thinks it's not visible, so layers can be retained forever. This 1.10107 + // is problematic when those layers uselessly hold on to precious 1.10108 + // resources like directly texturable memory. 1.10109 + // 1.10110 + // PresShell::SetIsActive() is the first C++ entry point at which we 1.10111 + // (i) know that our parent process wants our content to be hidden; 1.10112 + // and (ii) has easy access to the TabChild. So we use this 1.10113 + // notification to signal the TabChild to drop its layer tree and 1.10114 + // stop trying to repaint. 1.10115 + if (TabChild* tab = TabChild::GetFrom(this)) { 1.10116 + if (aIsActive) { 1.10117 + tab->MakeVisible(); 1.10118 + if (!mIsZombie) { 1.10119 + if (nsIFrame* root = mFrameConstructor->GetRootFrame()) { 1.10120 + FrameLayerBuilder::InvalidateAllLayersForFrame( 1.10121 + nsLayoutUtils::GetDisplayRootFrame(root)); 1.10122 + root->SchedulePaint(); 1.10123 + } 1.10124 + } 1.10125 + } else { 1.10126 + tab->MakeHidden(); 1.10127 + } 1.10128 + } 1.10129 + 1.10130 + return rv; 1.10131 +} 1.10132 + 1.10133 +/* 1.10134 + * Determines the current image locking state. Called when one of the 1.10135 + * dependent factors changes. 1.10136 + */ 1.10137 +nsresult 1.10138 +PresShell::UpdateImageLockingState() 1.10139 +{ 1.10140 + // We're locked if we're both thawed and active. 1.10141 + return mDocument->SetImageLockingState(!mFrozen && mIsActive); 1.10142 +} 1.10143 + 1.10144 +PresShell* 1.10145 +PresShell::GetRootPresShell() 1.10146 +{ 1.10147 + if (mPresContext) { 1.10148 + nsPresContext* rootPresContext = mPresContext->GetRootPresContext(); 1.10149 + if (rootPresContext) { 1.10150 + return static_cast<PresShell*>(rootPresContext->PresShell()); 1.10151 + } 1.10152 + } 1.10153 + return nullptr; 1.10154 +} 1.10155 + 1.10156 +void 1.10157 +PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, 1.10158 + nsArenaMemoryStats *aArenaObjectsSize, 1.10159 + size_t *aPresShellSize, 1.10160 + size_t *aStyleSetsSize, 1.10161 + size_t *aTextRunsSize, 1.10162 + size_t *aPresContextSize) 1.10163 +{ 1.10164 + mFrameArena.AddSizeOfExcludingThis(aMallocSizeOf, aArenaObjectsSize); 1.10165 + *aPresShellSize += aMallocSizeOf(this); 1.10166 + *aPresShellSize += aArenaObjectsSize->mOther; 1.10167 + 1.10168 + *aStyleSetsSize += StyleSet()->SizeOfIncludingThis(aMallocSizeOf); 1.10169 + 1.10170 + *aTextRunsSize += SizeOfTextRuns(aMallocSizeOf); 1.10171 + 1.10172 + *aPresContextSize += mPresContext->SizeOfIncludingThis(aMallocSizeOf); 1.10173 +} 1.10174 + 1.10175 +size_t 1.10176 +PresShell::SizeOfTextRuns(MallocSizeOf aMallocSizeOf) const 1.10177 +{ 1.10178 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.10179 + if (!rootFrame) { 1.10180 + return 0; 1.10181 + } 1.10182 + 1.10183 + // clear the TEXT_RUN_MEMORY_ACCOUNTED flags 1.10184 + nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, nullptr, 1.10185 + /* clear = */true); 1.10186 + 1.10187 + // collect the total memory in use for textruns 1.10188 + return nsLayoutUtils::SizeOfTextRunsForFrames(rootFrame, aMallocSizeOf, 1.10189 + /* clear = */false); 1.10190 +} 1.10191 + 1.10192 +void 1.10193 +nsIPresShell::MarkFixedFramesForReflow(IntrinsicDirty aIntrinsicDirty) 1.10194 +{ 1.10195 + nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); 1.10196 + if (rootFrame) { 1.10197 + const nsFrameList& childList = rootFrame->GetChildList(nsIFrame::kFixedList); 1.10198 + for (nsFrameList::Enumerator e(childList); !e.AtEnd(); e.Next()) { 1.10199 + FrameNeedsReflow(e.get(), aIntrinsicDirty, NS_FRAME_IS_DIRTY); 1.10200 + } 1.10201 + } 1.10202 +} 1.10203 + 1.10204 +void 1.10205 +nsIPresShell::SetScrollPositionClampingScrollPortSize(nscoord aWidth, nscoord aHeight) 1.10206 +{ 1.10207 + if (!mScrollPositionClampingScrollPortSizeSet || 1.10208 + mScrollPositionClampingScrollPortSize.width != aWidth || 1.10209 + mScrollPositionClampingScrollPortSize.height != aHeight) { 1.10210 + mScrollPositionClampingScrollPortSizeSet = true; 1.10211 + mScrollPositionClampingScrollPortSize.width = aWidth; 1.10212 + mScrollPositionClampingScrollPortSize.height = aHeight; 1.10213 + 1.10214 + MarkFixedFramesForReflow(eResize); 1.10215 + } 1.10216 +} 1.10217 + 1.10218 +void 1.10219 +nsIPresShell::SetContentDocumentFixedPositionMargins(const nsMargin& aMargins) 1.10220 +{ 1.10221 + if (mContentDocumentFixedPositionMargins == aMargins) { 1.10222 + return; 1.10223 + } 1.10224 + 1.10225 + mContentDocumentFixedPositionMargins = aMargins; 1.10226 + 1.10227 + MarkFixedFramesForReflow(eResize); 1.10228 +} 1.10229 + 1.10230 +void 1.10231 +PresShell::SetupFontInflation() 1.10232 +{ 1.10233 + mFontSizeInflationEmPerLine = nsLayoutUtils::FontSizeInflationEmPerLine(); 1.10234 + mFontSizeInflationMinTwips = nsLayoutUtils::FontSizeInflationMinTwips(); 1.10235 + mFontSizeInflationLineThreshold = nsLayoutUtils::FontSizeInflationLineThreshold(); 1.10236 + mFontSizeInflationForceEnabled = nsLayoutUtils::FontSizeInflationForceEnabled(); 1.10237 + mFontSizeInflationDisabledInMasterProcess = nsLayoutUtils::FontSizeInflationDisabledInMasterProcess(); 1.10238 + 1.10239 + NotifyFontSizeInflationEnabledIsDirty(); 1.10240 +} 1.10241 + 1.10242 +void 1.10243 +nsIPresShell::RecomputeFontSizeInflationEnabled() 1.10244 +{ 1.10245 + mFontSizeInflationEnabledIsDirty = false; 1.10246 + 1.10247 + MOZ_ASSERT(mPresContext, "our pres context should not be null"); 1.10248 + if ((FontSizeInflationEmPerLine() == 0 && 1.10249 + FontSizeInflationMinTwips() == 0) || mPresContext->IsChrome()) { 1.10250 + mFontSizeInflationEnabled = false; 1.10251 + return; 1.10252 + } 1.10253 + 1.10254 + // Force-enabling font inflation always trumps the heuristics here. 1.10255 + if (!FontSizeInflationForceEnabled()) { 1.10256 + if (TabChild* tab = TabChild::GetFrom(this)) { 1.10257 + // We're in a child process. Cancel inflation if we're not 1.10258 + // async-pan zoomed. 1.10259 + if (!tab->IsAsyncPanZoomEnabled()) { 1.10260 + mFontSizeInflationEnabled = false; 1.10261 + return; 1.10262 + } 1.10263 + } else if (XRE_GetProcessType() == GeckoProcessType_Default) { 1.10264 + // We're in the master process. Cancel inflation if it's been 1.10265 + // explicitly disabled. 1.10266 + if (FontSizeInflationDisabledInMasterProcess()) { 1.10267 + mFontSizeInflationEnabled = false; 1.10268 + return; 1.10269 + } 1.10270 + } 1.10271 + } 1.10272 + 1.10273 + // XXXjwir3: 1.10274 + // See bug 706918, comment 23 for more information on this particular section 1.10275 + // of the code. We're using "screen size" in place of the size of the content 1.10276 + // area, because on mobile, these are close or equal. This will work for our 1.10277 + // purposes (bug 706198), but it will need to be changed in the future to be 1.10278 + // more correct when we bring the rest of the viewport code into platform. 1.10279 + // We actually want the size of the content area, in the event that we don't 1.10280 + // have any metadata about the width and/or height. On mobile, the screen size 1.10281 + // and the size of the content area are very close, or the same value. 1.10282 + // In XUL fennec, the content area is the size of the <browser> widget, but 1.10283 + // in native fennec, the content area is the size of the Gecko LayerView 1.10284 + // object. 1.10285 + 1.10286 + // TODO: 1.10287 + // Once bug 716575 has been resolved, this code should be changed so that it 1.10288 + // does the right thing on all platforms. 1.10289 + nsresult rv; 1.10290 + nsCOMPtr<nsIScreenManager> screenMgr = 1.10291 + do_GetService("@mozilla.org/gfx/screenmanager;1", &rv); 1.10292 + if (!NS_SUCCEEDED(rv)) { 1.10293 + mFontSizeInflationEnabled = false; 1.10294 + return; 1.10295 + } 1.10296 + 1.10297 + nsCOMPtr<nsIScreen> screen; 1.10298 + screenMgr->GetPrimaryScreen(getter_AddRefs(screen)); 1.10299 + if (screen) { 1.10300 + int32_t screenLeft, screenTop, screenWidth, screenHeight; 1.10301 + screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight); 1.10302 + 1.10303 + nsViewportInfo vInf = 1.10304 + nsContentUtils::GetViewportInfo(GetDocument(), ScreenIntSize(screenWidth, screenHeight)); 1.10305 + 1.10306 + if (vInf.GetDefaultZoom() >= CSSToScreenScale(1.0f) || vInf.IsAutoSizeEnabled()) { 1.10307 + mFontSizeInflationEnabled = false; 1.10308 + return; 1.10309 + } 1.10310 + } 1.10311 + 1.10312 + mFontSizeInflationEnabled = true; 1.10313 +} 1.10314 + 1.10315 +bool 1.10316 +nsIPresShell::FontSizeInflationEnabled() 1.10317 +{ 1.10318 + if (mFontSizeInflationEnabledIsDirty) { 1.10319 + RecomputeFontSizeInflationEnabled(); 1.10320 + } 1.10321 + 1.10322 + return mFontSizeInflationEnabled; 1.10323 +} 1.10324 + 1.10325 +void 1.10326 +nsIPresShell::SetMaxLineBoxWidth(nscoord aMaxLineBoxWidth) 1.10327 +{ 1.10328 + NS_ASSERTION(aMaxLineBoxWidth >= 0, "attempting to set max line box width to a negative value"); 1.10329 + 1.10330 + if (mMaxLineBoxWidth != aMaxLineBoxWidth) { 1.10331 + mMaxLineBoxWidth = aMaxLineBoxWidth; 1.10332 + mReflowOnZoomPending = true; 1.10333 + FrameNeedsReflow(GetRootFrame(), eResize, NS_FRAME_HAS_DIRTY_CHILDREN); 1.10334 + } 1.10335 +} 1.10336 + 1.10337 +void 1.10338 +PresShell::PausePainting() 1.10339 +{ 1.10340 + if (GetPresContext()->RefreshDriver()->PresContext() != GetPresContext()) 1.10341 + return; 1.10342 + 1.10343 + mPaintingIsFrozen = true; 1.10344 + GetPresContext()->RefreshDriver()->Freeze(); 1.10345 +} 1.10346 + 1.10347 +void 1.10348 +PresShell::ResumePainting() 1.10349 +{ 1.10350 + if (GetPresContext()->RefreshDriver()->PresContext() != GetPresContext()) 1.10351 + return; 1.10352 + 1.10353 + mPaintingIsFrozen = false; 1.10354 + GetPresContext()->RefreshDriver()->Thaw(); 1.10355 +}