nsViewManager.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #define PL_ARENA_CONST_ALIGN_MASK (sizeof(void*)-1)
  6. #include "plarena.h"
  7. #include "nsAutoPtr.h"
  8. #include "nsViewManager.h"
  9. #include "nsGfxCIID.h"
  10. #include "nsView.h"
  11. #include "nsCOMPtr.h"
  12. #include "mozilla/MouseEvents.h"
  13. #include "nsRegion.h"
  14. #include "nsCOMArray.h"
  15. #include "nsIPluginWidget.h"
  16. #include "nsXULPopupManager.h"
  17. #include "nsIPresShell.h"
  18. #include "nsPresContext.h"
  19. #include "mozilla/StartupTimeline.h"
  20. #include "GeckoProfiler.h"
  21. #include "nsRefreshDriver.h"
  22. #include "mozilla/Preferences.h"
  23. #include "nsContentUtils.h" // for nsAutoScriptBlocker
  24. #include "nsLayoutUtils.h"
  25. #include "Layers.h"
  26. #include "gfxPlatform.h"
  27. #include "gfxPrefs.h"
  28. #include "nsIDocument.h"
  29. /**
  30. XXX TODO XXX
  31. DeCOMify newly private methods
  32. Optimize view storage
  33. */
  34. /**
  35. A note about platform assumptions:
  36. We assume that a widget is z-ordered on top of its parent.
  37. We do NOT assume anything about the relative z-ordering of sibling widgets. Even though
  38. we ask for a specific z-order, we don't assume that widget z-ordering actually works.
  39. */
  40. using namespace mozilla;
  41. using namespace mozilla::layers;
  42. #define NSCOORD_NONE INT32_MIN
  43. #undef DEBUG_MOUSE_LOCATION
  44. // Weakly held references to all of the view managers
  45. nsTArray<nsViewManager*>* nsViewManager::gViewManagers = nullptr;
  46. uint32_t nsViewManager::gLastUserEventTime = 0;
  47. nsViewManager::nsViewManager()
  48. : mDelayedResize(NSCOORD_NONE, NSCOORD_NONE)
  49. {
  50. mRootViewManager = this;
  51. if (gViewManagers == nullptr) {
  52. // Create an array to hold a list of view managers
  53. gViewManagers = new nsTArray<nsViewManager*>;
  54. }
  55. gViewManagers->AppendElement(this);
  56. // NOTE: we use a zeroing operator new, so all data members are
  57. // assumed to be cleared here.
  58. mHasPendingWidgetGeometryChanges = false;
  59. mRecursiveRefreshPending = false;
  60. }
  61. nsViewManager::~nsViewManager()
  62. {
  63. if (mRootView) {
  64. // Destroy any remaining views
  65. mRootView->Destroy();
  66. mRootView = nullptr;
  67. }
  68. if (!IsRootVM()) {
  69. // We have a strong ref to mRootViewManager
  70. NS_RELEASE(mRootViewManager);
  71. }
  72. NS_ASSERTION(gViewManagers != nullptr, "About to use null gViewManagers");
  73. #ifdef DEBUG
  74. bool removed =
  75. #endif
  76. gViewManagers->RemoveElement(this);
  77. NS_ASSERTION(removed, "Viewmanager instance was not in the global list of viewmanagers");
  78. if (gViewManagers->IsEmpty()) {
  79. // There aren't any more view managers so
  80. // release the global array of view managers
  81. delete gViewManagers;
  82. gViewManagers = nullptr;
  83. }
  84. MOZ_RELEASE_ASSERT(!mPresShell, "Releasing nsViewManager without having called Destroy on the PresShell!");
  85. }
  86. // We don't hold a reference to the presentation context because it
  87. // holds a reference to us.
  88. nsresult
  89. nsViewManager::Init(nsDeviceContext* aContext)
  90. {
  91. NS_PRECONDITION(nullptr != aContext, "null ptr");
  92. if (nullptr == aContext) {
  93. return NS_ERROR_NULL_POINTER;
  94. }
  95. if (nullptr != mContext) {
  96. return NS_ERROR_ALREADY_INITIALIZED;
  97. }
  98. mContext = aContext;
  99. return NS_OK;
  100. }
  101. nsView*
  102. nsViewManager::CreateView(const nsRect& aBounds,
  103. nsView* aParent,
  104. nsViewVisibility aVisibilityFlag)
  105. {
  106. nsView *v = new nsView(this, aVisibilityFlag);
  107. v->SetParent(aParent);
  108. v->SetPosition(aBounds.x, aBounds.y);
  109. nsRect dim(0, 0, aBounds.width, aBounds.height);
  110. v->SetDimensions(dim, false);
  111. return v;
  112. }
  113. void
  114. nsViewManager::SetRootView(nsView *aView)
  115. {
  116. NS_PRECONDITION(!aView || aView->GetViewManager() == this,
  117. "Unexpected viewmanager on root view");
  118. // Do NOT destroy the current root view. It's the caller's responsibility
  119. // to destroy it
  120. mRootView = aView;
  121. if (mRootView) {
  122. nsView* parent = mRootView->GetParent();
  123. if (parent) {
  124. // Calling InsertChild on |parent| will InvalidateHierarchy() on us, so
  125. // no need to set mRootViewManager ourselves here.
  126. parent->InsertChild(mRootView, nullptr);
  127. } else {
  128. InvalidateHierarchy();
  129. }
  130. mRootView->SetZIndex(false, 0);
  131. }
  132. // Else don't touch mRootViewManager
  133. }
  134. void
  135. nsViewManager::GetWindowDimensions(nscoord *aWidth, nscoord *aHeight)
  136. {
  137. if (nullptr != mRootView) {
  138. if (mDelayedResize == nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
  139. nsRect dim = mRootView->GetDimensions();
  140. *aWidth = dim.width;
  141. *aHeight = dim.height;
  142. } else {
  143. *aWidth = mDelayedResize.width;
  144. *aHeight = mDelayedResize.height;
  145. }
  146. }
  147. else
  148. {
  149. *aWidth = 0;
  150. *aHeight = 0;
  151. }
  152. }
  153. void nsViewManager::DoSetWindowDimensions(nscoord aWidth, nscoord aHeight)
  154. {
  155. nsRect oldDim = mRootView->GetDimensions();
  156. nsRect newDim(0, 0, aWidth, aHeight);
  157. // We care about resizes even when one dimension is already zero.
  158. if (!oldDim.IsEqualEdges(newDim)) {
  159. // Don't resize the widget. It is already being set elsewhere.
  160. mRootView->SetDimensions(newDim, true, false);
  161. if (mPresShell)
  162. mPresShell->ResizeReflow(aWidth, aHeight, oldDim.width, oldDim.height);
  163. }
  164. }
  165. bool
  166. nsViewManager::ShouldDelayResize() const
  167. {
  168. MOZ_ASSERT(mRootView);
  169. if (!mRootView->IsEffectivelyVisible() ||
  170. !mPresShell || !mPresShell->IsVisible()) {
  171. return true;
  172. }
  173. if (nsRefreshDriver* rd = mPresShell->GetRefreshDriver()) {
  174. if (rd->IsResizeSuppressed()) {
  175. return true;
  176. }
  177. }
  178. return false;
  179. }
  180. void
  181. nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight, bool aDelayResize)
  182. {
  183. if (mRootView) {
  184. if (!ShouldDelayResize() && !aDelayResize) {
  185. if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
  186. mDelayedResize != nsSize(aWidth, aHeight)) {
  187. // We have a delayed resize; that now obsolete size may already have
  188. // been flushed to the PresContext so we need to update the PresContext
  189. // with the new size because if the new size is exactly the same as the
  190. // root view's current size then DoSetWindowDimensions will not
  191. // request a resize reflow (which would correct it). See bug 617076.
  192. mDelayedResize = nsSize(aWidth, aHeight);
  193. FlushDelayedResize(false);
  194. }
  195. mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
  196. DoSetWindowDimensions(aWidth, aHeight);
  197. } else {
  198. mDelayedResize.SizeTo(aWidth, aHeight);
  199. if (mPresShell && mPresShell->GetDocument()) {
  200. nsIDocument* doc = mPresShell->GetDocument();
  201. doc->SetNeedStyleFlush();
  202. doc->SetNeedLayoutFlush();
  203. }
  204. }
  205. }
  206. }
  207. void
  208. nsViewManager::FlushDelayedResize(bool aDoReflow)
  209. {
  210. if (mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE)) {
  211. if (aDoReflow) {
  212. DoSetWindowDimensions(mDelayedResize.width, mDelayedResize.height);
  213. mDelayedResize.SizeTo(NSCOORD_NONE, NSCOORD_NONE);
  214. } else if (mPresShell && !mPresShell->GetIsViewportOverridden()) {
  215. nsPresContext* presContext = mPresShell->GetPresContext();
  216. if (presContext) {
  217. presContext->SetVisibleArea(nsRect(nsPoint(0, 0), mDelayedResize));
  218. }
  219. }
  220. }
  221. }
  222. // Convert aIn from being relative to and in appunits of aFromView, to being
  223. // relative to and in appunits of aToView.
  224. static nsRegion ConvertRegionBetweenViews(const nsRegion& aIn,
  225. nsView* aFromView,
  226. nsView* aToView)
  227. {
  228. nsRegion out = aIn;
  229. out.MoveBy(aFromView->GetOffsetTo(aToView));
  230. out = out.ScaleToOtherAppUnitsRoundOut(
  231. aFromView->GetViewManager()->AppUnitsPerDevPixel(),
  232. aToView->GetViewManager()->AppUnitsPerDevPixel());
  233. return out;
  234. }
  235. nsView* nsViewManager::GetDisplayRootFor(nsView* aView)
  236. {
  237. nsView *displayRoot = aView;
  238. for (;;) {
  239. nsView *displayParent = displayRoot->GetParent();
  240. if (!displayParent)
  241. return displayRoot;
  242. if (displayRoot->GetFloating() && !displayParent->GetFloating())
  243. return displayRoot;
  244. // If we have a combobox dropdown popup within a panel popup, both the view
  245. // for the dropdown popup and its parent will be floating, so we need to
  246. // distinguish this situation. We do this by looking for a widget. Any view
  247. // with a widget is a display root, except for plugins.
  248. nsIWidget* widget = displayRoot->GetWidget();
  249. if (widget && widget->WindowType() == eWindowType_popup) {
  250. NS_ASSERTION(displayRoot->GetFloating() && displayParent->GetFloating(),
  251. "this should only happen with floating views that have floating parents");
  252. return displayRoot;
  253. }
  254. displayRoot = displayParent;
  255. }
  256. }
  257. /**
  258. aRegion is given in device coordinates!!
  259. aContext may be null, in which case layers should be used for
  260. rendering.
  261. */
  262. void nsViewManager::Refresh(nsView* aView, const LayoutDeviceIntRegion& aRegion)
  263. {
  264. NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
  265. if (mPresShell && mPresShell->IsNeverPainting()) {
  266. return;
  267. }
  268. // damageRegion is the damaged area, in twips, relative to the view origin
  269. nsRegion damageRegion = aRegion.ToAppUnits(AppUnitsPerDevPixel());
  270. // move region from widget coordinates into view coordinates
  271. damageRegion.MoveBy(-aView->ViewToWidgetOffset());
  272. if (damageRegion.IsEmpty()) {
  273. #ifdef DEBUG_roc
  274. nsRect viewRect = aView->GetDimensions();
  275. nsRect damageRect = damageRegion.GetBounds();
  276. printf_stderr("XXX Damage rectangle (%d,%d,%d,%d) does not intersect the widget's view (%d,%d,%d,%d)!\n",
  277. damageRect.x, damageRect.y, damageRect.width, damageRect.height,
  278. viewRect.x, viewRect.y, viewRect.width, viewRect.height);
  279. #endif
  280. return;
  281. }
  282. nsIWidget *widget = aView->GetWidget();
  283. if (!widget) {
  284. return;
  285. }
  286. NS_ASSERTION(!IsPainting(), "recursive painting not permitted");
  287. if (IsPainting()) {
  288. RootViewManager()->mRecursiveRefreshPending = true;
  289. return;
  290. }
  291. {
  292. nsAutoScriptBlocker scriptBlocker;
  293. SetPainting(true);
  294. NS_ASSERTION(GetDisplayRootFor(aView) == aView,
  295. "Widgets that we paint must all be display roots");
  296. if (mPresShell) {
  297. #ifdef MOZ_DUMP_PAINTING
  298. if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  299. printf_stderr("--COMPOSITE-- %p\n", mPresShell);
  300. }
  301. #endif
  302. uint32_t paintFlags = nsIPresShell::PAINT_COMPOSITE;
  303. LayerManager *manager = widget->GetLayerManager();
  304. if (!manager->NeedsWidgetInvalidation()) {
  305. manager->FlushRendering();
  306. } else {
  307. mPresShell->Paint(aView, damageRegion,
  308. paintFlags);
  309. }
  310. #ifdef MOZ_DUMP_PAINTING
  311. if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  312. printf_stderr("--ENDCOMPOSITE--\n");
  313. }
  314. #endif
  315. mozilla::StartupTimeline::RecordOnce(mozilla::StartupTimeline::FIRST_PAINT);
  316. }
  317. SetPainting(false);
  318. }
  319. if (RootViewManager()->mRecursiveRefreshPending) {
  320. RootViewManager()->mRecursiveRefreshPending = false;
  321. InvalidateAllViews();
  322. }
  323. }
  324. void
  325. nsViewManager::ProcessPendingUpdatesForView(nsView* aView,
  326. bool aFlushDirtyRegion)
  327. {
  328. NS_ASSERTION(IsRootVM(), "Updates will be missed");
  329. if (!aView) {
  330. return;
  331. }
  332. nsCOMPtr<nsIPresShell> rootShell(mPresShell);
  333. nsTArray<nsCOMPtr<nsIWidget> > widgets;
  334. aView->GetViewManager()->ProcessPendingUpdatesRecurse(aView, widgets);
  335. for (uint32_t i = 0; i < widgets.Length(); ++i) {
  336. nsView* view = nsView::GetViewFor(widgets[i]);
  337. if (view) {
  338. if (view->mNeedsWindowPropertiesSync) {
  339. view->mNeedsWindowPropertiesSync = false;
  340. if (nsViewManager* vm = view->GetViewManager()) {
  341. if (nsIPresShell* ps = vm->GetPresShell()) {
  342. ps->SyncWindowProperties(view);
  343. }
  344. }
  345. }
  346. }
  347. view = nsView::GetViewFor(widgets[i]);
  348. if (view) {
  349. view->ResetWidgetBounds(false, true);
  350. }
  351. }
  352. if (rootShell->GetViewManager() != this) {
  353. return; // presentation might have been torn down
  354. }
  355. if (aFlushDirtyRegion) {
  356. profiler_tracing("Paint", "DisplayList", TRACING_INTERVAL_START);
  357. nsAutoScriptBlocker scriptBlocker;
  358. SetPainting(true);
  359. for (uint32_t i = 0; i < widgets.Length(); ++i) {
  360. nsIWidget* widget = widgets[i];
  361. nsView* view = nsView::GetViewFor(widget);
  362. if (view) {
  363. view->GetViewManager()->ProcessPendingUpdatesPaint(widget);
  364. }
  365. }
  366. SetPainting(false);
  367. profiler_tracing("Paint", "DisplayList", TRACING_INTERVAL_END);
  368. }
  369. }
  370. void
  371. nsViewManager::ProcessPendingUpdatesRecurse(nsView* aView,
  372. nsTArray<nsCOMPtr<nsIWidget> >& aWidgets)
  373. {
  374. if (mPresShell && mPresShell->IsNeverPainting()) {
  375. return;
  376. }
  377. for (nsView* childView = aView->GetFirstChild(); childView;
  378. childView = childView->GetNextSibling()) {
  379. childView->GetViewManager()->
  380. ProcessPendingUpdatesRecurse(childView, aWidgets);
  381. }
  382. nsIWidget* widget = aView->GetWidget();
  383. if (widget) {
  384. aWidgets.AppendElement(widget);
  385. } else {
  386. FlushDirtyRegionToWidget(aView);
  387. }
  388. }
  389. void
  390. nsViewManager::ProcessPendingUpdatesPaint(nsIWidget* aWidget)
  391. {
  392. if (aWidget->NeedsPaint()) {
  393. // If an ancestor widget was hidden and then shown, we could
  394. // have a delayed resize to handle.
  395. for (RefPtr<nsViewManager> vm = this; vm;
  396. vm = vm->mRootView->GetParent()
  397. ? vm->mRootView->GetParent()->GetViewManager()
  398. : nullptr) {
  399. if (vm->mDelayedResize != nsSize(NSCOORD_NONE, NSCOORD_NONE) &&
  400. vm->mRootView->IsEffectivelyVisible() &&
  401. vm->mPresShell && vm->mPresShell->IsVisible()) {
  402. vm->FlushDelayedResize(true);
  403. }
  404. }
  405. nsView* view = nsView::GetViewFor(aWidget);
  406. if (!view) {
  407. NS_ERROR("FlushDelayedResize destroyed the nsView?");
  408. return;
  409. }
  410. nsIWidgetListener* previousListener = aWidget->GetPreviouslyAttachedWidgetListener();
  411. if (previousListener &&
  412. previousListener != view &&
  413. view->IsPrimaryFramePaintSuppressed()) {
  414. return;
  415. }
  416. if (mPresShell) {
  417. #ifdef MOZ_DUMP_PAINTING
  418. if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  419. printf_stderr("---- PAINT START ----PresShell(%p), nsView(%p), nsIWidget(%p)\n",
  420. mPresShell, view, aWidget);
  421. }
  422. #endif
  423. mPresShell->Paint(view, nsRegion(), nsIPresShell::PAINT_LAYERS);
  424. view->SetForcedRepaint(false);
  425. #ifdef MOZ_DUMP_PAINTING
  426. if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
  427. printf_stderr("---- PAINT END ----\n");
  428. }
  429. #endif
  430. }
  431. }
  432. FlushDirtyRegionToWidget(nsView::GetViewFor(aWidget));
  433. }
  434. void nsViewManager::FlushDirtyRegionToWidget(nsView* aView)
  435. {
  436. NS_ASSERTION(aView->GetViewManager() == this,
  437. "FlushDirtyRegionToWidget called on view we don't own");
  438. if (!aView->HasNonEmptyDirtyRegion())
  439. return;
  440. nsRegion* dirtyRegion = aView->GetDirtyRegion();
  441. nsView* nearestViewWithWidget = aView;
  442. while (!nearestViewWithWidget->HasWidget() &&
  443. nearestViewWithWidget->GetParent()) {
  444. nearestViewWithWidget = nearestViewWithWidget->GetParent();
  445. }
  446. nsRegion r =
  447. ConvertRegionBetweenViews(*dirtyRegion, aView, nearestViewWithWidget);
  448. // If we draw the frame counter we need to make sure we invalidate the area
  449. // for it to make it on screen
  450. if (gfxPrefs::DrawFrameCounter()) {
  451. nsRect counterBounds = ToAppUnits(gfxPlatform::FrameCounterBounds(), AppUnitsPerDevPixel());
  452. r.OrWith(counterBounds);
  453. }
  454. nsViewManager* widgetVM = nearestViewWithWidget->GetViewManager();
  455. widgetVM->InvalidateWidgetArea(nearestViewWithWidget, r);
  456. dirtyRegion->SetEmpty();
  457. }
  458. void
  459. nsViewManager::InvalidateView(nsView *aView)
  460. {
  461. // Mark the entire view as damaged
  462. InvalidateView(aView, aView->GetDimensions());
  463. }
  464. static void
  465. AddDirtyRegion(nsView *aView, const nsRegion &aDamagedRegion)
  466. {
  467. nsRegion* dirtyRegion = aView->GetDirtyRegion();
  468. if (!dirtyRegion)
  469. return;
  470. dirtyRegion->Or(*dirtyRegion, aDamagedRegion);
  471. dirtyRegion->SimplifyOutward(8);
  472. }
  473. void
  474. nsViewManager::PostPendingUpdate()
  475. {
  476. nsViewManager* rootVM = RootViewManager();
  477. rootVM->mHasPendingWidgetGeometryChanges = true;
  478. if (rootVM->mPresShell) {
  479. rootVM->mPresShell->ScheduleViewManagerFlush();
  480. }
  481. }
  482. /**
  483. * @param aDamagedRegion this region, relative to aWidgetView, is invalidated in
  484. * every widget child of aWidgetView, plus aWidgetView's own widget
  485. */
  486. void
  487. nsViewManager::InvalidateWidgetArea(nsView *aWidgetView,
  488. const nsRegion &aDamagedRegion)
  489. {
  490. NS_ASSERTION(aWidgetView->GetViewManager() == this,
  491. "InvalidateWidgetArea called on view we don't own");
  492. nsIWidget* widget = aWidgetView->GetWidget();
  493. #if 0
  494. nsRect dbgBounds = aDamagedRegion.GetBounds();
  495. printf("InvalidateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
  496. aWidgetView, aWidgetView->IsAttachedToTopLevel(),
  497. widget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height);
  498. #endif
  499. // If the widget is hidden, it don't cover nothing
  500. if (widget && !widget->IsVisible()) {
  501. return;
  502. }
  503. if (!widget) {
  504. // The root view or a scrolling view might not have a widget
  505. // (for example, during printing). We get here when we scroll
  506. // during printing to show selected options in a listbox, for example.
  507. return;
  508. }
  509. // Update all child widgets with the damage. In the process,
  510. // accumulate the union of all the child widget areas, or at least
  511. // some subset of that.
  512. nsRegion children;
  513. if (widget->GetTransparencyMode() != eTransparencyTransparent) {
  514. for (nsIWidget* childWidget = widget->GetFirstChild();
  515. childWidget;
  516. childWidget = childWidget->GetNextSibling()) {
  517. nsView* view = nsView::GetViewFor(childWidget);
  518. NS_ASSERTION(view != aWidgetView, "will recur infinitely");
  519. nsWindowType type = childWidget->WindowType();
  520. if (view && childWidget->IsVisible() && type != eWindowType_popup) {
  521. NS_ASSERTION(childWidget->IsPlugin(),
  522. "Only plugin or popup widgets can be children!");
  523. // We do not need to invalidate in plugin widgets, but we should
  524. // exclude them from the invalidation region.
  525. // GetBounds should compensate for chrome on a toplevel widget
  526. LayoutDeviceIntRect bounds = childWidget->GetBounds();
  527. nsTArray<LayoutDeviceIntRect> clipRects;
  528. childWidget->GetWindowClipRegion(&clipRects);
  529. for (uint32_t i = 0; i < clipRects.Length(); ++i) {
  530. nsRect rr = LayoutDeviceIntRect::ToAppUnits(
  531. clipRects[i] + bounds.TopLeft(), AppUnitsPerDevPixel());
  532. children.Or(children, rr - aWidgetView->ViewToWidgetOffset());
  533. children.SimplifyInward(20);
  534. }
  535. }
  536. }
  537. }
  538. nsRegion leftOver;
  539. leftOver.Sub(aDamagedRegion, children);
  540. if (!leftOver.IsEmpty()) {
  541. for (auto iter = leftOver.RectIter(); !iter.Done(); iter.Next()) {
  542. LayoutDeviceIntRect bounds = ViewToWidget(aWidgetView, iter.Get());
  543. widget->Invalidate(bounds);
  544. }
  545. }
  546. }
  547. static bool
  548. ShouldIgnoreInvalidation(nsViewManager* aVM)
  549. {
  550. while (aVM) {
  551. nsIPresShell* shell = aVM->GetPresShell();
  552. if (!shell || shell->ShouldIgnoreInvalidation()) {
  553. return true;
  554. }
  555. nsView* view = aVM->GetRootView()->GetParent();
  556. aVM = view ? view->GetViewManager() : nullptr;
  557. }
  558. return false;
  559. }
  560. void
  561. nsViewManager::InvalidateView(nsView *aView, const nsRect &aRect)
  562. {
  563. // If painting is suppressed in the presshell or an ancestor drop all
  564. // invalidates, it will invalidate everything when it unsuppresses.
  565. if (ShouldIgnoreInvalidation(this)) {
  566. return;
  567. }
  568. InvalidateViewNoSuppression(aView, aRect);
  569. }
  570. void
  571. nsViewManager::InvalidateViewNoSuppression(nsView *aView,
  572. const nsRect &aRect)
  573. {
  574. NS_PRECONDITION(nullptr != aView, "null view");
  575. NS_ASSERTION(aView->GetViewManager() == this,
  576. "InvalidateViewNoSuppression called on view we don't own");
  577. nsRect damagedRect(aRect);
  578. if (damagedRect.IsEmpty()) {
  579. return;
  580. }
  581. nsView* displayRoot = GetDisplayRootFor(aView);
  582. nsViewManager* displayRootVM = displayRoot->GetViewManager();
  583. // Propagate the update to the displayRoot, since iframes, for example,
  584. // can overlap each other and be translucent. So we have to possibly
  585. // invalidate our rect in each of the widgets we have lying about.
  586. damagedRect.MoveBy(aView->GetOffsetTo(displayRoot));
  587. int32_t rootAPD = displayRootVM->AppUnitsPerDevPixel();
  588. int32_t APD = AppUnitsPerDevPixel();
  589. damagedRect = damagedRect.ScaleToOtherAppUnitsRoundOut(APD, rootAPD);
  590. // accumulate this rectangle in the view's dirty region, so we can
  591. // process it later.
  592. AddDirtyRegion(displayRoot, nsRegion(damagedRect));
  593. }
  594. void
  595. nsViewManager::InvalidateAllViews()
  596. {
  597. if (RootViewManager() != this) {
  598. return RootViewManager()->InvalidateAllViews();
  599. }
  600. InvalidateViews(mRootView);
  601. }
  602. void nsViewManager::InvalidateViews(nsView *aView)
  603. {
  604. // Invalidate this view.
  605. InvalidateView(aView);
  606. // Invalidate all children as well.
  607. nsView* childView = aView->GetFirstChild();
  608. while (nullptr != childView) {
  609. childView->GetViewManager()->InvalidateViews(childView);
  610. childView = childView->GetNextSibling();
  611. }
  612. }
  613. void nsViewManager::WillPaintWindow(nsIWidget* aWidget)
  614. {
  615. RefPtr<nsIWidget> widget(aWidget);
  616. if (widget) {
  617. nsView* view = nsView::GetViewFor(widget);
  618. LayerManager* manager = widget->GetLayerManager();
  619. if (view &&
  620. (view->ForcedRepaint() || !manager->NeedsWidgetInvalidation())) {
  621. ProcessPendingUpdates();
  622. // Re-get the view pointer here since the ProcessPendingUpdates might have
  623. // destroyed it during CallWillPaintOnObservers.
  624. view = nsView::GetViewFor(widget);
  625. if (view) {
  626. view->SetForcedRepaint(false);
  627. }
  628. }
  629. }
  630. nsCOMPtr<nsIPresShell> shell = mPresShell;
  631. if (shell) {
  632. shell->WillPaintWindow();
  633. }
  634. }
  635. bool nsViewManager::PaintWindow(nsIWidget* aWidget,
  636. LayoutDeviceIntRegion aRegion)
  637. {
  638. if (!aWidget || !mContext)
  639. return false;
  640. NS_ASSERTION(IsPaintingAllowed(),
  641. "shouldn't be receiving paint events while painting is disallowed!");
  642. // Get the view pointer here since NS_WILL_PAINT might have
  643. // destroyed it during CallWillPaintOnObservers (bug 378273).
  644. nsView* view = nsView::GetViewFor(aWidget);
  645. if (view && !aRegion.IsEmpty()) {
  646. Refresh(view, aRegion);
  647. }
  648. return true;
  649. }
  650. void nsViewManager::DidPaintWindow()
  651. {
  652. nsCOMPtr<nsIPresShell> shell = mPresShell;
  653. if (shell) {
  654. shell->DidPaintWindow();
  655. }
  656. }
  657. void
  658. nsViewManager::DispatchEvent(WidgetGUIEvent *aEvent,
  659. nsView* aView,
  660. nsEventStatus* aStatus)
  661. {
  662. PROFILER_LABEL("nsViewManager", "DispatchEvent",
  663. js::ProfileEntry::Category::EVENTS);
  664. WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
  665. if ((mouseEvent &&
  666. // Ignore mouse events that we synthesize.
  667. mouseEvent->mReason == WidgetMouseEvent::eReal &&
  668. // Ignore mouse exit and enter (we'll get moves if the user
  669. // is really moving the mouse) since we get them when we
  670. // create and destroy widgets.
  671. mouseEvent->mMessage != eMouseExitFromWidget &&
  672. mouseEvent->mMessage != eMouseEnterIntoWidget) ||
  673. aEvent->HasKeyEventMessage() ||
  674. aEvent->HasIMEEventMessage() ||
  675. aEvent->mMessage == ePluginInputEvent) {
  676. gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
  677. }
  678. // Find the view whose coordinates system we're in.
  679. nsView* view = aView;
  680. bool dispatchUsingCoordinates = aEvent->IsUsingCoordinates();
  681. if (dispatchUsingCoordinates) {
  682. // Will dispatch using coordinates. Pretty bogus but it's consistent
  683. // with what presshell does.
  684. view = GetDisplayRootFor(view);
  685. }
  686. // If the view has no frame, look for a view that does.
  687. nsIFrame* frame = view->GetFrame();
  688. if (!frame &&
  689. (dispatchUsingCoordinates || aEvent->HasKeyEventMessage() ||
  690. aEvent->IsIMERelatedEvent() ||
  691. aEvent->IsNonRetargetedNativeEventDelivererForPlugin() ||
  692. aEvent->HasPluginActivationEventMessage())) {
  693. while (view && !view->GetFrame()) {
  694. view = view->GetParent();
  695. }
  696. if (view) {
  697. frame = view->GetFrame();
  698. }
  699. }
  700. if (nullptr != frame) {
  701. // Hold a refcount to the presshell. The continued existence of the
  702. // presshell will delay deletion of this view hierarchy should the event
  703. // want to cause its destruction in, say, some JavaScript event handler.
  704. nsCOMPtr<nsIPresShell> shell = view->GetViewManager()->GetPresShell();
  705. if (shell) {
  706. shell->HandleEvent(frame, aEvent, false, aStatus);
  707. return;
  708. }
  709. }
  710. *aStatus = nsEventStatus_eIgnore;
  711. }
  712. // Recursively reparent widgets if necessary
  713. void nsViewManager::ReparentChildWidgets(nsView* aView, nsIWidget *aNewWidget)
  714. {
  715. NS_PRECONDITION(aNewWidget, "");
  716. if (aView->HasWidget()) {
  717. // Check to see if the parent widget is the
  718. // same as the new parent. If not then reparent
  719. // the widget, otherwise there is nothing more
  720. // to do for the view and its descendants
  721. nsIWidget* widget = aView->GetWidget();
  722. nsIWidget* parentWidget = widget->GetParent();
  723. if (parentWidget) {
  724. // Child widget
  725. if (parentWidget != aNewWidget) {
  726. #ifdef DEBUG
  727. nsresult rv =
  728. #endif
  729. widget->SetParent(aNewWidget);
  730. NS_ASSERTION(NS_SUCCEEDED(rv), "SetParent failed!");
  731. }
  732. } else {
  733. // Toplevel widget (popup, dialog, etc)
  734. widget->ReparentNativeWidget(aNewWidget);
  735. }
  736. return;
  737. }
  738. // Need to check each of the views children to see
  739. // if they have a widget and reparent it.
  740. for (nsView *kid = aView->GetFirstChild(); kid; kid = kid->GetNextSibling()) {
  741. ReparentChildWidgets(kid, aNewWidget);
  742. }
  743. }
  744. // Reparent a view and its descendant views widgets if necessary
  745. void nsViewManager::ReparentWidgets(nsView* aView, nsView *aParent)
  746. {
  747. NS_PRECONDITION(aParent, "Must have a parent");
  748. NS_PRECONDITION(aView, "Must have a view");
  749. // Quickly determine whether the view has pre-existing children or a
  750. // widget. In most cases the view will not have any pre-existing
  751. // children when this is called. Only in the case
  752. // where a view has been reparented by removing it from
  753. // a reinserting it into a new location in the view hierarchy do we
  754. // have to consider reparenting the existing widgets for the view and
  755. // it's descendants.
  756. if (aView->HasWidget() || aView->GetFirstChild()) {
  757. nsIWidget* parentWidget = aParent->GetNearestWidget(nullptr);
  758. if (parentWidget) {
  759. ReparentChildWidgets(aView, parentWidget);
  760. return;
  761. }
  762. NS_WARNING("Can not find a widget for the parent view");
  763. }
  764. }
  765. void
  766. nsViewManager::InsertChild(nsView *aParent, nsView *aChild, nsView *aSibling,
  767. bool aAfter)
  768. {
  769. NS_PRECONDITION(nullptr != aParent, "null ptr");
  770. NS_PRECONDITION(nullptr != aChild, "null ptr");
  771. NS_ASSERTION(aSibling == nullptr || aSibling->GetParent() == aParent,
  772. "tried to insert view with invalid sibling");
  773. NS_ASSERTION(!IsViewInserted(aChild), "tried to insert an already-inserted view");
  774. if ((nullptr != aParent) && (nullptr != aChild))
  775. {
  776. // if aAfter is set, we will insert the child after 'prev' (i.e. after 'kid' in document
  777. // order, otherwise after 'kid' (i.e. before 'kid' in document order).
  778. if (nullptr == aSibling) {
  779. if (aAfter) {
  780. // insert at end of document order, i.e., before first view
  781. // this is the common case, by far
  782. aParent->InsertChild(aChild, nullptr);
  783. ReparentWidgets(aChild, aParent);
  784. } else {
  785. // insert at beginning of document order, i.e., after last view
  786. nsView *kid = aParent->GetFirstChild();
  787. nsView *prev = nullptr;
  788. while (kid) {
  789. prev = kid;
  790. kid = kid->GetNextSibling();
  791. }
  792. // prev is last view or null if there are no children
  793. aParent->InsertChild(aChild, prev);
  794. ReparentWidgets(aChild, aParent);
  795. }
  796. } else {
  797. nsView *kid = aParent->GetFirstChild();
  798. nsView *prev = nullptr;
  799. while (kid && aSibling != kid) {
  800. //get the next sibling view
  801. prev = kid;
  802. kid = kid->GetNextSibling();
  803. }
  804. NS_ASSERTION(kid != nullptr,
  805. "couldn't find sibling in child list");
  806. if (aAfter) {
  807. // insert after 'kid' in document order, i.e. before in view order
  808. aParent->InsertChild(aChild, prev);
  809. ReparentWidgets(aChild, aParent);
  810. } else {
  811. // insert before 'kid' in document order, i.e. after in view order
  812. aParent->InsertChild(aChild, kid);
  813. ReparentWidgets(aChild, aParent);
  814. }
  815. }
  816. // if the parent view is marked as "floating", make the newly added view float as well.
  817. if (aParent->GetFloating())
  818. aChild->SetFloating(true);
  819. }
  820. }
  821. void
  822. nsViewManager::InsertChild(nsView *aParent, nsView *aChild, int32_t aZIndex)
  823. {
  824. // no-one really calls this with anything other than aZIndex == 0 on a fresh view
  825. // XXX this method should simply be eliminated and its callers redirected to the real method
  826. SetViewZIndex(aChild, false, aZIndex);
  827. InsertChild(aParent, aChild, nullptr, true);
  828. }
  829. void
  830. nsViewManager::RemoveChild(nsView *aChild)
  831. {
  832. NS_ASSERTION(aChild, "aChild must not be null");
  833. nsView* parent = aChild->GetParent();
  834. if (nullptr != parent) {
  835. NS_ASSERTION(aChild->GetViewManager() == this ||
  836. parent->GetViewManager() == this, "wrong view manager");
  837. parent->RemoveChild(aChild);
  838. }
  839. }
  840. void
  841. nsViewManager::MoveViewTo(nsView *aView, nscoord aX, nscoord aY)
  842. {
  843. NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
  844. aView->SetPosition(aX, aY);
  845. }
  846. void
  847. nsViewManager::ResizeView(nsView *aView, const nsRect &aRect, bool aRepaintExposedAreaOnly)
  848. {
  849. NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
  850. nsRect oldDimensions = aView->GetDimensions();
  851. if (!oldDimensions.IsEqualEdges(aRect)) {
  852. aView->SetDimensions(aRect, true);
  853. }
  854. // Note that if layout resizes the view and the view has a custom clip
  855. // region set, then we expect layout to update the clip region too. Thus
  856. // in the case where mClipRect has been optimized away to just be a null
  857. // pointer, and this resize is implicitly changing the clip rect, it's OK
  858. // because layout will change it back again if necessary.
  859. }
  860. void
  861. nsViewManager::SetViewFloating(nsView *aView, bool aFloating)
  862. {
  863. NS_ASSERTION(!(nullptr == aView), "no view");
  864. aView->SetFloating(aFloating);
  865. }
  866. void
  867. nsViewManager::SetViewVisibility(nsView *aView, nsViewVisibility aVisible)
  868. {
  869. NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
  870. if (aVisible != aView->GetVisibility()) {
  871. aView->SetVisibility(aVisible);
  872. }
  873. }
  874. bool nsViewManager::IsViewInserted(nsView *aView)
  875. {
  876. if (mRootView == aView) {
  877. return true;
  878. } else if (aView->GetParent() == nullptr) {
  879. return false;
  880. } else {
  881. nsView* view = aView->GetParent()->GetFirstChild();
  882. while (view != nullptr) {
  883. if (view == aView) {
  884. return true;
  885. }
  886. view = view->GetNextSibling();
  887. }
  888. return false;
  889. }
  890. }
  891. void
  892. nsViewManager::SetViewZIndex(nsView *aView, bool aAutoZIndex, int32_t aZIndex)
  893. {
  894. NS_ASSERTION((aView != nullptr), "no view");
  895. // don't allow the root view's z-index to be changed. It should always be zero.
  896. // This could be removed and replaced with a style rule, or just removed altogether, with interesting consequences
  897. if (aView == mRootView) {
  898. return;
  899. }
  900. if (aAutoZIndex) {
  901. aZIndex = 0;
  902. }
  903. aView->SetZIndex(aAutoZIndex, aZIndex);
  904. }
  905. nsViewManager*
  906. nsViewManager::IncrementDisableRefreshCount()
  907. {
  908. if (!IsRootVM()) {
  909. return RootViewManager()->IncrementDisableRefreshCount();
  910. }
  911. ++mRefreshDisableCount;
  912. return this;
  913. }
  914. void
  915. nsViewManager::DecrementDisableRefreshCount()
  916. {
  917. NS_ASSERTION(IsRootVM(), "Should only be called on root");
  918. --mRefreshDisableCount;
  919. NS_ASSERTION(mRefreshDisableCount >= 0, "Invalid refresh disable count!");
  920. }
  921. void
  922. nsViewManager::GetRootWidget(nsIWidget **aWidget)
  923. {
  924. if (!mRootView) {
  925. *aWidget = nullptr;
  926. return;
  927. }
  928. if (mRootView->HasWidget()) {
  929. *aWidget = mRootView->GetWidget();
  930. NS_ADDREF(*aWidget);
  931. return;
  932. }
  933. if (mRootView->GetParent()) {
  934. mRootView->GetParent()->GetViewManager()->GetRootWidget(aWidget);
  935. return;
  936. }
  937. *aWidget = nullptr;
  938. }
  939. LayoutDeviceIntRect
  940. nsViewManager::ViewToWidget(nsView* aView, const nsRect& aRect) const
  941. {
  942. NS_ASSERTION(aView->GetViewManager() == this, "wrong view manager");
  943. // account for the view's origin not lining up with the widget's
  944. nsRect rect = aRect + aView->ViewToWidgetOffset();
  945. // finally, convert to device coordinates.
  946. return LayoutDeviceIntRect::FromUnknownRect(
  947. rect.ToOutsidePixels(AppUnitsPerDevPixel()));
  948. }
  949. void
  950. nsViewManager::IsPainting(bool& aIsPainting)
  951. {
  952. aIsPainting = IsPainting();
  953. }
  954. void
  955. nsViewManager::ProcessPendingUpdates()
  956. {
  957. if (!IsRootVM()) {
  958. RootViewManager()->ProcessPendingUpdates();
  959. return;
  960. }
  961. // Flush things like reflows by calling WillPaint on observer presShells.
  962. if (mPresShell) {
  963. mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush();
  964. RefPtr<nsViewManager> strongThis(this);
  965. CallWillPaintOnObservers();
  966. ProcessPendingUpdatesForView(mRootView, true);
  967. }
  968. }
  969. void
  970. nsViewManager::UpdateWidgetGeometry()
  971. {
  972. if (!IsRootVM()) {
  973. RootViewManager()->UpdateWidgetGeometry();
  974. return;
  975. }
  976. if (mHasPendingWidgetGeometryChanges) {
  977. mHasPendingWidgetGeometryChanges = false;
  978. RefPtr<nsViewManager> strongThis(this);
  979. ProcessPendingUpdatesForView(mRootView, false);
  980. }
  981. }
  982. void
  983. nsViewManager::CallWillPaintOnObservers()
  984. {
  985. NS_PRECONDITION(IsRootVM(), "Must be root VM for this to be called!");
  986. if (NS_WARN_IF(!gViewManagers)) {
  987. return;
  988. }
  989. uint32_t index;
  990. for (index = 0; index < gViewManagers->Length(); index++) {
  991. nsViewManager* vm = gViewManagers->ElementAt(index);
  992. if (vm->RootViewManager() == this) {
  993. // One of our kids.
  994. if (vm->mRootView && vm->mRootView->IsEffectivelyVisible()) {
  995. nsCOMPtr<nsIPresShell> shell = vm->GetPresShell();
  996. if (shell) {
  997. shell->WillPaint();
  998. }
  999. }
  1000. }
  1001. }
  1002. }
  1003. void
  1004. nsViewManager::GetLastUserEventTime(uint32_t& aTime)
  1005. {
  1006. aTime = gLastUserEventTime;
  1007. }
  1008. void
  1009. nsViewManager::InvalidateHierarchy()
  1010. {
  1011. if (mRootView) {
  1012. if (!IsRootVM()) {
  1013. NS_RELEASE(mRootViewManager);
  1014. }
  1015. nsView *parent = mRootView->GetParent();
  1016. if (parent) {
  1017. mRootViewManager = parent->GetViewManager()->RootViewManager();
  1018. NS_ADDREF(mRootViewManager);
  1019. NS_ASSERTION(mRootViewManager != this,
  1020. "Root view had a parent, but it has the same view manager");
  1021. } else {
  1022. mRootViewManager = this;
  1023. }
  1024. }
  1025. }