You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LayoutManager.java 74KB

hace 11 años
hace 11 años
hace 11 años
hace 11 años
hace 11 años
hace 11 años
hace 11 años
hace 11 años
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865
  1. /*
  2. * Copyright 2000-2018 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client;
  17. import java.util.Collection;
  18. import java.util.HashMap;
  19. import java.util.HashSet;
  20. import java.util.Map;
  21. import java.util.Set;
  22. import java.util.logging.Level;
  23. import java.util.logging.Logger;
  24. import com.google.gwt.core.client.Duration;
  25. import com.google.gwt.core.client.JsArrayString;
  26. import com.google.gwt.dom.client.Element;
  27. import com.google.gwt.dom.client.Style;
  28. import com.google.gwt.dom.client.Style.Overflow;
  29. import com.google.gwt.user.client.Timer;
  30. import com.vaadin.client.MeasuredSize.MeasureResult;
  31. import com.vaadin.client.ui.ManagedLayout;
  32. import com.vaadin.client.ui.PostLayoutListener;
  33. import com.vaadin.client.ui.SimpleManagedLayout;
  34. import com.vaadin.client.ui.VNotification;
  35. import com.vaadin.client.ui.layout.ElementResizeEvent;
  36. import com.vaadin.client.ui.layout.ElementResizeListener;
  37. import com.vaadin.client.ui.layout.LayoutDependencyTree;
  38. public class LayoutManager {
  39. private static final String STATE_CHANGE_MESSAGE = "Cannot run layout while processing state change from the server.";
  40. private static final String LOOP_ABORT_MESSAGE = "Aborting layout after 100 passes. This would probably be an infinite loop.";
  41. private static final boolean debugLogging = false;
  42. private ApplicationConnection connection;
  43. private final Set<Element> measuredNonConnectorElements = new HashSet<Element>();
  44. private final MeasuredSize nullSize = new MeasuredSize();
  45. private LayoutDependencyTree currentDependencyTree;
  46. private FastStringSet needsHorizontalLayout = FastStringSet.create();
  47. private FastStringSet needsVerticalLayout = FastStringSet.create();
  48. private FastStringSet needsMeasure = FastStringSet.create();
  49. private FastStringSet pendingOverflowFixes = FastStringSet.create();
  50. private final Map<Element, Collection<ElementResizeListener>> elementResizeListeners = new HashMap<Element, Collection<ElementResizeListener>>();
  51. private final Set<Element> listenersToFire = new HashSet<Element>();
  52. private boolean layoutPending = false;
  53. private Timer layoutTimer = new Timer() {
  54. @Override
  55. public void run() {
  56. layoutNow();
  57. }
  58. };
  59. private boolean everythingNeedsMeasure = false;
  60. /**
  61. * Sets the application connection this instance is connected to. Called
  62. * internally by the framework.
  63. *
  64. * @param connection
  65. * the application connection this instance is connected to
  66. */
  67. public void setConnection(ApplicationConnection connection) {
  68. if (this.connection != null) {
  69. throw new RuntimeException(
  70. "LayoutManager connection can never be changed");
  71. }
  72. this.connection = connection;
  73. }
  74. /**
  75. * Returns the application connection for this layout manager.
  76. *
  77. * @return connection
  78. */
  79. protected ApplicationConnection getConnection() {
  80. return connection;
  81. }
  82. /**
  83. * Gets the layout manager associated with the given
  84. * {@link ApplicationConnection}.
  85. *
  86. * @param connection
  87. * the application connection to get a layout manager for
  88. * @return the layout manager associated with the provided application
  89. * connection
  90. */
  91. public static LayoutManager get(ApplicationConnection connection) {
  92. return connection.getLayoutManager();
  93. }
  94. /**
  95. * Registers that a ManagedLayout is depending on the size of an Element.
  96. * This causes this layout manager to measure the element in the beginning
  97. * of every layout phase and call the appropriate layout method of the
  98. * managed layout if the size of the element has changed.
  99. *
  100. * @param owner
  101. * the ManagedLayout that depends on an element
  102. * @param element
  103. * the Element that should be measured
  104. */
  105. public void registerDependency(ManagedLayout owner, Element element) {
  106. MeasuredSize measuredSize = ensureMeasured(element);
  107. setNeedsLayout(owner);
  108. measuredSize.addDependent(owner.getConnectorId());
  109. }
  110. private MeasuredSize ensureMeasured(Element element) {
  111. MeasuredSize measuredSize = getMeasuredSize(element, null);
  112. if (measuredSize == null) {
  113. measuredSize = new MeasuredSize();
  114. if (ConnectorMap.get(connection).getConnector(element) == null) {
  115. measuredNonConnectorElements.add(element);
  116. }
  117. setMeasuredSize(element, measuredSize);
  118. }
  119. return measuredSize;
  120. }
  121. private boolean needsMeasure(Element e) {
  122. ComponentConnector connector = connection.getConnectorMap()
  123. .getConnector(e);
  124. if (connector != null && needsMeasureForManagedLayout(connector)) {
  125. return true;
  126. } else if (elementResizeListeners.containsKey(e)) {
  127. return true;
  128. } else if (getMeasuredSize(e, nullSize).hasDependents()) {
  129. return true;
  130. } else {
  131. return false;
  132. }
  133. }
  134. private boolean needsMeasureForManagedLayout(ComponentConnector connector) {
  135. if (connector instanceof ManagedLayout) {
  136. return true;
  137. } else if (connector.getParent() instanceof ManagedLayout) {
  138. return true;
  139. } else {
  140. return false;
  141. }
  142. }
  143. /**
  144. * Assigns a measured size to an element. Method defined as protected to
  145. * allow separate implementation for IE8.
  146. *
  147. * @param element
  148. * the dom element to attach the measured size to
  149. * @param measuredSize
  150. * the measured size to attach to the element. If
  151. * <code>null</code>, any previous measured size is removed.
  152. */
  153. protected native void setMeasuredSize(Element element,
  154. MeasuredSize measuredSize)
  155. /*-{
  156. if (measuredSize) {
  157. element.vMeasuredSize = measuredSize;
  158. } else {
  159. delete element.vMeasuredSize;
  160. }
  161. }-*/;
  162. /**
  163. * Gets the measured size for an element. Method defined as protected to
  164. * allow separate implementation for IE8.
  165. *
  166. * @param element
  167. * The element to get measured size for
  168. * @param defaultSize
  169. * The size to return if no measured size could be found
  170. * @return The measured size for the element or {@literal defaultSize}
  171. */
  172. protected native MeasuredSize getMeasuredSize(Element element,
  173. MeasuredSize defaultSize)
  174. /*-{
  175. return element.vMeasuredSize || defaultSize;
  176. }-*/;
  177. private final MeasuredSize getMeasuredSize(Element element) {
  178. MeasuredSize measuredSize = getMeasuredSize(element, null);
  179. if (measuredSize == null) {
  180. measuredSize = new MeasuredSize();
  181. setMeasuredSize(element, measuredSize);
  182. }
  183. return measuredSize;
  184. }
  185. /**
  186. * Registers that a ManagedLayout is no longer depending on the size of an
  187. * Element.
  188. *
  189. * @see #registerDependency(ManagedLayout, Element)
  190. *
  191. * @param owner
  192. * the ManagedLayout no longer depends on an element
  193. * @param element
  194. * the Element that that no longer needs to be measured
  195. */
  196. public void unregisterDependency(ManagedLayout owner, Element element) {
  197. MeasuredSize measuredSize = getMeasuredSize(element, null);
  198. if (measuredSize == null) {
  199. return;
  200. }
  201. measuredSize.removeDependent(owner.getConnectorId());
  202. stopMeasuringIfUnecessary(element);
  203. }
  204. public boolean isLayoutRunning() {
  205. return currentDependencyTree != null;
  206. }
  207. private void countLayout(FastStringMap<Integer> layoutCounts,
  208. ManagedLayout layout) {
  209. Integer count = layoutCounts.get(layout.getConnectorId());
  210. if (count == null) {
  211. count = Integer.valueOf(0);
  212. } else {
  213. count = Integer.valueOf(count.intValue() + 1);
  214. }
  215. layoutCounts.put(layout.getConnectorId(), count);
  216. if (count.intValue() > 2) {
  217. getLogger().severe(Util.getConnectorString(layout)
  218. + " has been layouted " + count.intValue() + " times");
  219. }
  220. }
  221. public void layoutLater() {
  222. if (!layoutPending) {
  223. layoutPending = true;
  224. layoutTimer.schedule(100);
  225. }
  226. }
  227. public void layoutNow() {
  228. if (isLayoutRunning()) {
  229. throw new IllegalStateException(
  230. "Can't start a new layout phase before the previous layout phase ends.");
  231. }
  232. if (connection.getMessageHandler().isUpdatingState()) {
  233. // If assertions are enabled, throw an exception
  234. assert false : STATE_CHANGE_MESSAGE;
  235. // Else just log a warning and postpone the layout
  236. getLogger().warning(STATE_CHANGE_MESSAGE);
  237. // Framework will call layoutNow when the state update is completed
  238. return;
  239. }
  240. layoutPending = false;
  241. layoutTimer.cancel();
  242. try {
  243. currentDependencyTree = new LayoutDependencyTree(connection);
  244. doLayout();
  245. } finally {
  246. currentDependencyTree = null;
  247. }
  248. }
  249. /**
  250. * Called once per iteration in the layout loop before size calculations so
  251. * different browsers quirks can be handled. Mainly this is currently for
  252. * the IE8 permutation.
  253. */
  254. protected void performBrowserLayoutHacks() {
  255. // Permutations implement this
  256. }
  257. private void doLayout() {
  258. getLogger().info("Starting layout phase");
  259. Profiler.enter("LayoutManager phase init");
  260. FastStringMap<Integer> layoutCounts = FastStringMap.create();
  261. int passes = 0;
  262. Duration totalDuration = new Duration();
  263. ConnectorMap connectorMap = ConnectorMap.get(connection);
  264. JsArrayString dump = needsHorizontalLayout.dump();
  265. int dumpLength = dump.length();
  266. for (int i = 0; i < dumpLength; i++) {
  267. String layoutId = dump.get(i);
  268. currentDependencyTree.setNeedsHorizontalLayout(layoutId, true);
  269. }
  270. dump = needsVerticalLayout.dump();
  271. dumpLength = dump.length();
  272. for (int i = 0; i < dumpLength; i++) {
  273. String layoutId = dump.get(i);
  274. currentDependencyTree.setNeedsVerticalLayout(layoutId, true);
  275. }
  276. needsHorizontalLayout = FastStringSet.create();
  277. needsVerticalLayout = FastStringSet.create();
  278. dump = needsMeasure.dump();
  279. dumpLength = dump.length();
  280. for (int i = 0; i < dumpLength; i++) {
  281. ServerConnector connector = connectorMap.getConnector(dump.get(i));
  282. if (connector != null) {
  283. currentDependencyTree
  284. .setNeedsMeasure((ComponentConnector) connector, true);
  285. }
  286. }
  287. needsMeasure = FastStringSet.create();
  288. measureNonConnectors();
  289. Profiler.leave("LayoutManager phase init");
  290. while (true) {
  291. Profiler.enter("Layout pass");
  292. passes++;
  293. performBrowserLayoutHacks();
  294. Profiler.enter("Layout measure connectors");
  295. int measuredConnectorCount = measureConnectors(
  296. currentDependencyTree, everythingNeedsMeasure);
  297. Profiler.leave("Layout measure connectors");
  298. everythingNeedsMeasure = false;
  299. if (measuredConnectorCount == 0) {
  300. getLogger().info("No more changes in pass " + passes);
  301. Profiler.leave("Layout pass");
  302. break;
  303. }
  304. int firedListeners = 0;
  305. if (!listenersToFire.isEmpty()) {
  306. HashSet<Element> listenersCopy = new HashSet<Element>(
  307. listenersToFire);
  308. listenersToFire.clear();
  309. firedListeners = listenersToFire.size();
  310. Profiler.enter("Layout fire resize events");
  311. for (Element element : listenersCopy) {
  312. Collection<ElementResizeListener> listeners = elementResizeListeners
  313. .get(element);
  314. if (listeners != null) {
  315. Profiler.enter(
  316. "Layout fire resize events - listeners not null");
  317. Profiler.enter(
  318. "ElementResizeListener.onElementResize copy list");
  319. ElementResizeListener[] array = listeners.toArray(
  320. new ElementResizeListener[listeners.size()]);
  321. Profiler.leave(
  322. "ElementResizeListener.onElementResize copy list");
  323. ElementResizeEvent event = new ElementResizeEvent(this,
  324. element);
  325. for (ElementResizeListener listener : array) {
  326. try {
  327. String key = null;
  328. if (Profiler.isEnabled()) {
  329. Profiler.enter(
  330. "ElementResizeListener.onElementResize construct profiler key");
  331. key = "ElementResizeListener.onElementResize for "
  332. + listener.getClass()
  333. .getSimpleName();
  334. Profiler.leave(
  335. "ElementResizeListener.onElementResize construct profiler key");
  336. Profiler.enter(key);
  337. }
  338. listener.onElementResize(event);
  339. if (Profiler.isEnabled()) {
  340. Profiler.leave(key);
  341. }
  342. } catch (RuntimeException e) {
  343. getLogger().log(Level.SEVERE,
  344. "Error in resize listener", e);
  345. }
  346. }
  347. Profiler.leave(
  348. "Layout fire resize events - listeners not null");
  349. }
  350. }
  351. Profiler.leave("Layout fire resize events");
  352. }
  353. Profiler.enter("LayoutManager handle ManagedLayout");
  354. FastStringSet updatedSet = FastStringSet.create();
  355. int layoutCount = 0;
  356. while (currentDependencyTree.hasHorizontalConnectorToLayout()
  357. || currentDependencyTree.hasVerticaConnectorToLayout()) {
  358. JsArrayString layoutTargets = currentDependencyTree
  359. .getHorizontalLayoutTargetsJsArray();
  360. int length = layoutTargets.length();
  361. for (int i = 0; i < length; i++) {
  362. ManagedLayout layout = (ManagedLayout) connectorMap
  363. .getConnector(layoutTargets.get(i));
  364. if (layout instanceof DirectionalManagedLayout) {
  365. currentDependencyTree
  366. .markAsHorizontallyLayouted(layout);
  367. DirectionalManagedLayout cl = (DirectionalManagedLayout) layout;
  368. try {
  369. String key = null;
  370. if (Profiler.isEnabled()) {
  371. key = "layoutHorizontally() for "
  372. + cl.getClass().getSimpleName();
  373. Profiler.enter(key);
  374. }
  375. cl.layoutHorizontally();
  376. layoutCount++;
  377. if (Profiler.isEnabled()) {
  378. Profiler.leave(key);
  379. }
  380. } catch (RuntimeException e) {
  381. getLogger().log(Level.SEVERE,
  382. "Error in ManagedLayout handling", e);
  383. }
  384. countLayout(layoutCounts, cl);
  385. } else {
  386. currentDependencyTree
  387. .markAsHorizontallyLayouted(layout);
  388. currentDependencyTree.markAsVerticallyLayouted(layout);
  389. SimpleManagedLayout rr = (SimpleManagedLayout) layout;
  390. try {
  391. String key = null;
  392. if (Profiler.isEnabled()) {
  393. key = "layout() for "
  394. + rr.getClass().getSimpleName();
  395. Profiler.enter(key);
  396. }
  397. rr.layout();
  398. layoutCount++;
  399. if (Profiler.isEnabled()) {
  400. Profiler.leave(key);
  401. }
  402. } catch (RuntimeException e) {
  403. getLogger().log(Level.SEVERE,
  404. "Error in SimpleManagedLayout (horizontal) handling",
  405. e);
  406. }
  407. countLayout(layoutCounts, rr);
  408. }
  409. if (debugLogging) {
  410. updatedSet.add(layout.getConnectorId());
  411. }
  412. }
  413. layoutTargets = currentDependencyTree
  414. .getVerticalLayoutTargetsJsArray();
  415. length = layoutTargets.length();
  416. for (int i = 0; i < length; i++) {
  417. ManagedLayout layout = (ManagedLayout) connectorMap
  418. .getConnector(layoutTargets.get(i));
  419. if (layout instanceof DirectionalManagedLayout) {
  420. currentDependencyTree.markAsVerticallyLayouted(layout);
  421. DirectionalManagedLayout cl = (DirectionalManagedLayout) layout;
  422. try {
  423. String key = null;
  424. if (Profiler.isEnabled()) {
  425. key = "layoutVertically() for "
  426. + cl.getClass().getSimpleName();
  427. Profiler.enter(key);
  428. }
  429. cl.layoutVertically();
  430. layoutCount++;
  431. if (Profiler.isEnabled()) {
  432. Profiler.leave(key);
  433. }
  434. } catch (RuntimeException e) {
  435. getLogger().log(Level.SEVERE,
  436. "Error in DirectionalManagedLayout handling",
  437. e);
  438. }
  439. countLayout(layoutCounts, cl);
  440. } else {
  441. currentDependencyTree
  442. .markAsHorizontallyLayouted(layout);
  443. currentDependencyTree.markAsVerticallyLayouted(layout);
  444. SimpleManagedLayout rr = (SimpleManagedLayout) layout;
  445. try {
  446. String key = null;
  447. if (Profiler.isEnabled()) {
  448. key = "layout() for "
  449. + rr.getClass().getSimpleName();
  450. Profiler.enter(key);
  451. }
  452. rr.layout();
  453. layoutCount++;
  454. if (Profiler.isEnabled()) {
  455. Profiler.leave(key);
  456. }
  457. } catch (RuntimeException e) {
  458. getLogger().log(Level.SEVERE,
  459. "Error in SimpleManagedLayout (vertical) handling",
  460. e);
  461. }
  462. countLayout(layoutCounts, rr);
  463. }
  464. if (debugLogging) {
  465. updatedSet.add(layout.getConnectorId());
  466. }
  467. }
  468. }
  469. Profiler.leave("LayoutManager handle ManagedLayout");
  470. if (debugLogging) {
  471. JsArrayString changedCids = updatedSet.dump();
  472. StringBuilder b = new StringBuilder(" ");
  473. b.append(changedCids.length());
  474. b.append(" requestLayout invocations ");
  475. if (changedCids.length() < 30) {
  476. for (int i = 0; i < changedCids.length(); i++) {
  477. if (i != 0) {
  478. b.append(", ");
  479. } else {
  480. b.append(": ");
  481. }
  482. String connectorString = changedCids.get(i);
  483. if (changedCids.length() < 10) {
  484. ServerConnector connector = ConnectorMap
  485. .get(connection)
  486. .getConnector(connectorString);
  487. connectorString = Util
  488. .getConnectorString(connector);
  489. }
  490. b.append(connectorString);
  491. }
  492. }
  493. getLogger().info(b.toString());
  494. }
  495. Profiler.leave("Layout pass");
  496. getLogger().info("Pass " + passes + " measured "
  497. + measuredConnectorCount + " elements, fired "
  498. + firedListeners + " listeners and did " + layoutCount
  499. + " layouts.");
  500. if (passes > 100) {
  501. getLogger().severe(LOOP_ABORT_MESSAGE);
  502. if (ApplicationConfiguration.isDebugMode()) {
  503. VNotification
  504. .createNotification(VNotification.DELAY_FOREVER,
  505. connection.getUIConnector().getWidget())
  506. .show(LOOP_ABORT_MESSAGE, VNotification.CENTERED,
  507. "error");
  508. }
  509. break;
  510. }
  511. }
  512. Profiler.enter("layout PostLayoutListener");
  513. JsArrayObject<ComponentConnector> componentConnectors = connectorMap
  514. .getComponentConnectorsAsJsArray();
  515. int size = componentConnectors.size();
  516. for (int i = 0; i < size; i++) {
  517. ComponentConnector connector = componentConnectors.get(i);
  518. if (connector instanceof PostLayoutListener) {
  519. String key = null;
  520. if (Profiler.isEnabled()) {
  521. key = "layout PostLayoutListener for "
  522. + connector.getClass().getSimpleName();
  523. Profiler.enter(key);
  524. }
  525. ((PostLayoutListener) connector).postLayout();
  526. if (Profiler.isEnabled()) {
  527. Profiler.leave(key);
  528. }
  529. }
  530. }
  531. Profiler.leave("layout PostLayoutListener");
  532. cleanMeasuredSizes();
  533. // Ensure temporary variables are cleaned
  534. if (!pendingOverflowFixes.isEmpty()) {
  535. getLogger().warning(
  536. "pendingOverflowFixes is not empty at the end of doLayout: "
  537. + pendingOverflowFixes.dump());
  538. pendingOverflowFixes = FastStringSet.create();
  539. }
  540. getLogger().info("Total layout phase time: "
  541. + totalDuration.elapsedMillis() + "ms");
  542. }
  543. private void logConnectorStatus(int connectorId) {
  544. currentDependencyTree.logDependencyStatus(
  545. (ComponentConnector) ConnectorMap.get(connection)
  546. .getConnector(Integer.toString(connectorId)));
  547. }
  548. private int measureConnectors(LayoutDependencyTree layoutDependencyTree,
  549. boolean measureAll) {
  550. Profiler.enter("Layout overflow fix handling");
  551. JsArrayString pendingOverflowConnectorsIds = pendingOverflowFixes
  552. .dump();
  553. int pendingOverflowCount = pendingOverflowConnectorsIds.length();
  554. ConnectorMap connectorMap = ConnectorMap.get(connection);
  555. if (pendingOverflowCount > 0) {
  556. HashMap<Element, String> originalOverflows = new HashMap<Element, String>();
  557. FastStringSet delayedOverflowFixes = FastStringSet.create();
  558. // First set overflow to hidden (and save previous value so it can
  559. // be restored later)
  560. for (int i = 0; i < pendingOverflowCount; i++) {
  561. String connectorId = pendingOverflowConnectorsIds.get(i);
  562. ComponentConnector componentConnector = (ComponentConnector) connectorMap
  563. .getConnector(connectorId);
  564. if (delayOverflowFix(componentConnector)) {
  565. delayedOverflowFixes.add(connectorId);
  566. continue;
  567. }
  568. if (debugLogging) {
  569. getLogger().info("Doing overflow fix for "
  570. + Util.getConnectorString(componentConnector)
  571. + " in " + Util.getConnectorString(
  572. componentConnector.getParent()));
  573. }
  574. Profiler.enter("Overflow fix apply");
  575. Element parentElement = componentConnector.getWidget()
  576. .getElement().getParentElement();
  577. Style style = parentElement.getStyle();
  578. String originalOverflow = style.getOverflow();
  579. if (originalOverflow != null
  580. && !originalOverflows.containsKey(parentElement)) {
  581. // Store original value for restore, but only the first time
  582. // the value is changed
  583. originalOverflows.put(parentElement, originalOverflow);
  584. }
  585. style.setOverflow(Overflow.HIDDEN);
  586. Profiler.leave("Overflow fix apply");
  587. }
  588. pendingOverflowFixes.removeAll(delayedOverflowFixes);
  589. JsArrayString remainingOverflowFixIds = pendingOverflowFixes.dump();
  590. int remainingCount = remainingOverflowFixIds.length();
  591. Profiler.enter("Overflow fix reflow");
  592. // Then ensure all scrolling elements are reflowed by measuring
  593. for (int i = 0; i < remainingCount; i++) {
  594. ComponentConnector componentConnector = (ComponentConnector) connectorMap
  595. .getConnector(remainingOverflowFixIds.get(i));
  596. componentConnector.getWidget().getElement().getParentElement()
  597. .getOffsetHeight();
  598. }
  599. Profiler.leave("Overflow fix reflow");
  600. Profiler.enter("Overflow fix restore");
  601. // Finally restore old overflow value and update bookkeeping
  602. for (int i = 0; i < remainingCount; i++) {
  603. String connectorId = remainingOverflowFixIds.get(i);
  604. ComponentConnector componentConnector = (ComponentConnector) connectorMap
  605. .getConnector(connectorId);
  606. Element parentElement = componentConnector.getWidget()
  607. .getElement().getParentElement();
  608. parentElement.getStyle().setProperty("overflow",
  609. originalOverflows.get(parentElement));
  610. layoutDependencyTree.setNeedsMeasure(componentConnector, true);
  611. }
  612. Profiler.leave("Overflow fix restore");
  613. if (!pendingOverflowFixes.isEmpty()) {
  614. getLogger().info(
  615. "Did overflow fix for " + remainingCount + " elements");
  616. }
  617. pendingOverflowFixes = delayedOverflowFixes;
  618. }
  619. Profiler.leave("Layout overflow fix handling");
  620. int measureCount = 0;
  621. if (measureAll) {
  622. Profiler.enter("Layout measureAll");
  623. JsArrayObject<ComponentConnector> allConnectors = connectorMap
  624. .getComponentConnectorsAsJsArray();
  625. int size = allConnectors.size();
  626. // Find connectors that should actually be measured
  627. JsArrayObject<ComponentConnector> connectors = JsArrayObject
  628. .createArray().cast();
  629. for (int i = 0; i < size; i++) {
  630. ComponentConnector candidate = allConnectors.get(i);
  631. if (!Util.shouldSkipMeasurementOfConnector(candidate)
  632. && needsMeasure(candidate.getWidget().getElement())) {
  633. connectors.add(candidate);
  634. }
  635. }
  636. int connectorCount = connectors.size();
  637. for (int i = 0; i < connectorCount; i++) {
  638. measureConnector(connectors.get(i));
  639. }
  640. for (int i = 0; i < connectorCount; i++) {
  641. layoutDependencyTree.setNeedsMeasure(connectors.get(i), false);
  642. }
  643. measureCount += connectorCount;
  644. Profiler.leave("Layout measureAll");
  645. }
  646. Profiler.enter("Layout measure from tree");
  647. while (layoutDependencyTree.hasConnectorsToMeasure()) {
  648. JsArrayString measureTargets = layoutDependencyTree
  649. .getMeasureTargetsJsArray();
  650. int length = measureTargets.length();
  651. for (int i = 0; i < length; i++) {
  652. ComponentConnector connector = (ComponentConnector) connectorMap
  653. .getConnector(measureTargets.get(i));
  654. measureConnector(connector);
  655. measureCount++;
  656. }
  657. for (int i = 0; i < length; i++) {
  658. ComponentConnector connector = (ComponentConnector) connectorMap
  659. .getConnector(measureTargets.get(i));
  660. layoutDependencyTree.setNeedsMeasure(connector, false);
  661. }
  662. }
  663. Profiler.leave("Layout measure from tree");
  664. return measureCount;
  665. }
  666. /*
  667. * Delay the overflow fix if the involved connectors might still change
  668. */
  669. private boolean delayOverflowFix(ComponentConnector componentConnector) {
  670. if (!currentDependencyTree.noMoreChangesExpected(componentConnector)) {
  671. return true;
  672. }
  673. ServerConnector parent = componentConnector.getParent();
  674. if (parent instanceof ComponentConnector && !currentDependencyTree
  675. .noMoreChangesExpected((ComponentConnector) parent)) {
  676. return true;
  677. }
  678. return false;
  679. }
  680. private void measureConnector(ComponentConnector connector) {
  681. Profiler.enter("LayoutManager.measureConnector");
  682. Element element = connector.getWidget().getElement();
  683. MeasuredSize measuredSize = getMeasuredSize(element);
  684. MeasureResult measureResult = measuredAndUpdate(element, measuredSize);
  685. if (measureResult.isChanged()) {
  686. onConnectorChange(connector, measureResult.isWidthChanged(),
  687. measureResult.isHeightChanged());
  688. }
  689. Profiler.leave("LayoutManager.measureConnector");
  690. }
  691. private void onConnectorChange(ComponentConnector connector,
  692. boolean widthChanged, boolean heightChanged) {
  693. Profiler.enter("LayoutManager.onConnectorChange");
  694. Profiler.enter("LayoutManager.onConnectorChange setNeedsOverflowFix");
  695. setNeedsOverflowFix(connector);
  696. Profiler.leave("LayoutManager.onConnectorChange setNeedsOverflowFix");
  697. Profiler.enter("LayoutManager.onConnectorChange heightChanged");
  698. if (heightChanged) {
  699. currentDependencyTree.markHeightAsChanged(connector);
  700. }
  701. Profiler.leave("LayoutManager.onConnectorChange heightChanged");
  702. Profiler.enter("LayoutManager.onConnectorChange widthChanged");
  703. if (widthChanged) {
  704. currentDependencyTree.markWidthAsChanged(connector);
  705. }
  706. Profiler.leave("LayoutManager.onConnectorChange widthChanged");
  707. Profiler.leave("LayoutManager.onConnectorChange");
  708. }
  709. private void setNeedsOverflowFix(ComponentConnector connector) {
  710. // IE9 doesn't need the original fix, but for some reason it needs this
  711. if (BrowserInfo.get().requiresOverflowAutoFix()
  712. || BrowserInfo.get().isIE9()) {
  713. ComponentConnector scrollingBoundary = currentDependencyTree
  714. .getScrollingBoundary(connector);
  715. if (scrollingBoundary != null) {
  716. pendingOverflowFixes.add(scrollingBoundary.getConnectorId());
  717. }
  718. }
  719. }
  720. private void measureNonConnectors() {
  721. Profiler.enter("LayoutManager.measureNonConenctors");
  722. for (Element element : measuredNonConnectorElements) {
  723. measuredAndUpdate(element, getMeasuredSize(element, null));
  724. }
  725. Profiler.leave("LayoutManager.measureNonConenctors");
  726. getLogger().info("Measured " + measuredNonConnectorElements.size()
  727. + " non connector elements");
  728. }
  729. private MeasureResult measuredAndUpdate(Element element,
  730. MeasuredSize measuredSize) {
  731. MeasureResult measureResult = measuredSize.measure(element);
  732. if (measureResult.isChanged()) {
  733. notifyListenersAndDepdendents(element,
  734. measureResult.isWidthChanged(),
  735. measureResult.isHeightChanged());
  736. }
  737. return measureResult;
  738. }
  739. private void notifyListenersAndDepdendents(Element element,
  740. boolean widthChanged, boolean heightChanged) {
  741. assert widthChanged || heightChanged;
  742. Profiler.enter("LayoutManager.notifyListenersAndDepdendents");
  743. MeasuredSize measuredSize = getMeasuredSize(element, nullSize);
  744. JsArrayString dependents = measuredSize.getDependents();
  745. for (int i = 0; i < dependents.length(); i++) {
  746. String pid = dependents.get(i);
  747. if (pid != null) {
  748. if (heightChanged) {
  749. currentDependencyTree.setNeedsVerticalLayout(pid, true);
  750. }
  751. if (widthChanged) {
  752. currentDependencyTree.setNeedsHorizontalLayout(pid, true);
  753. }
  754. }
  755. }
  756. if (elementResizeListeners.containsKey(element)) {
  757. listenersToFire.add(element);
  758. }
  759. Profiler.leave("LayoutManager.notifyListenersAndDepdendents");
  760. }
  761. private static boolean isManagedLayout(ComponentConnector connector) {
  762. return connector instanceof ManagedLayout;
  763. }
  764. public void forceLayout() {
  765. ConnectorMap connectorMap = connection.getConnectorMap();
  766. JsArrayObject<ComponentConnector> componentConnectors = connectorMap
  767. .getComponentConnectorsAsJsArray();
  768. int size = componentConnectors.size();
  769. for (int i = 0; i < size; i++) {
  770. ComponentConnector connector = componentConnectors.get(i);
  771. if (connector instanceof ManagedLayout) {
  772. setNeedsLayout((ManagedLayout) connector);
  773. }
  774. }
  775. setEverythingNeedsMeasure();
  776. layoutNow();
  777. }
  778. /**
  779. * Marks that a ManagedLayout should be layouted in the next layout phase
  780. * even if none of the elements managed by the layout have been resized.
  781. * <p>
  782. * This method should not be invoked during a layout phase since it only
  783. * controls what will happen in the beginning of the next phase. If you want
  784. * to explicitly cause some layout to be considered in an ongoing layout
  785. * phase, you should use {@link #setNeedsMeasure(ComponentConnector)}
  786. * instead.
  787. *
  788. * @param layout
  789. * the managed layout that should be layouted
  790. */
  791. public final void setNeedsLayout(ManagedLayout layout) {
  792. setNeedsHorizontalLayout(layout);
  793. setNeedsVerticalLayout(layout);
  794. }
  795. /**
  796. * Marks that a ManagedLayout should be layouted horizontally in the next
  797. * layout phase even if none of the elements managed by the layout have been
  798. * resized horizontally.
  799. * <p>
  800. * For SimpleManagedLayout which is always layouted in both directions, this
  801. * has the same effect as {@link #setNeedsLayout(ManagedLayout)}.
  802. * <p>
  803. * This method should not be invoked during a layout phase since it only
  804. * controls what will happen in the beginning of the next phase. If you want
  805. * to explicitly cause some layout to be considered in an ongoing layout
  806. * phase, you should use {@link #setNeedsMeasure(ComponentConnector)}
  807. * instead.
  808. *
  809. * @param layout
  810. * the managed layout that should be layouted
  811. */
  812. public final void setNeedsHorizontalLayout(ManagedLayout layout) {
  813. if (isLayoutRunning()) {
  814. getLogger().warning(
  815. "setNeedsHorizontalLayout should not be run while a layout phase is in progress.");
  816. }
  817. needsHorizontalLayout.add(layout.getConnectorId());
  818. }
  819. /**
  820. * Marks that a ManagedLayout should be layouted vertically in the next
  821. * layout phase even if none of the elements managed by the layout have been
  822. * resized vertically.
  823. * <p>
  824. * For SimpleManagedLayout which is always layouted in both directions, this
  825. * has the same effect as {@link #setNeedsLayout(ManagedLayout)}.
  826. * <p>
  827. * This method should not be invoked during a layout phase since it only
  828. * controls what will happen in the beginning of the next phase. If you want
  829. * to explicitly cause some layout to be considered in an ongoing layout
  830. * phase, you should use {@link #setNeedsMeasure(ComponentConnector)}
  831. * instead.
  832. *
  833. * @param layout
  834. * the managed layout that should be layouted
  835. */
  836. public final void setNeedsVerticalLayout(ManagedLayout layout) {
  837. if (isLayoutRunning()) {
  838. getLogger().warning(
  839. "setNeedsVerticalLayout should not be run while a layout phase is in progress.");
  840. }
  841. needsVerticalLayout.add(layout.getConnectorId());
  842. }
  843. /**
  844. * Gets the outer height (including margins, paddings and borders) of the
  845. * given element, provided that it has been measured. These elements are
  846. * guaranteed to be measured:
  847. * <ul>
  848. * <li>ManagedLayouts and their child Connectors
  849. * <li>Elements for which there is at least one ElementResizeListener
  850. * <li>Elements for which at least one ManagedLayout has registered a
  851. * dependency
  852. * </ul>
  853. *
  854. * -1 is returned if the element has not been measured. If 0 is returned, it
  855. * might indicate that the element is not attached to the DOM.
  856. * <p>
  857. * The value returned by this method is always rounded up. To get the exact
  858. * outer width, use {@link #getOuterHeightDouble(Element)}
  859. *
  860. * @param element
  861. * the element to get the measured size for
  862. * @return the measured outer height (including margins, paddings and
  863. * borders) of the element in pixels.
  864. */
  865. public final int getOuterHeight(Element element) {
  866. assert needsMeasure(
  867. element) : "Getting measurement for element that is not measured";
  868. return (int) Math
  869. .ceil(getMeasuredSize(element, nullSize).getOuterHeight());
  870. }
  871. /**
  872. * Gets the outer height (including margins, paddings and borders) of the
  873. * given element, provided that it has been measured. These elements are
  874. * guaranteed to be measured:
  875. * <ul>
  876. * <li>ManagedLayouts and their child Connectors
  877. * <li>Elements for which there is at least one ElementResizeListener
  878. * <li>Elements for which at least one ManagedLayout has registered a
  879. * dependency
  880. * </ul>
  881. *
  882. * -1 is returned if the element has not been measured. If 0 is returned, it
  883. * might indicate that the element is not attached to the DOM.
  884. *
  885. * @since 7.5.1
  886. * @param element
  887. * the element to get the measured size for
  888. * @return the measured outer height (including margins, paddings and
  889. * borders) of the element in pixels.
  890. */
  891. public final double getOuterHeightDouble(Element element) {
  892. assert needsMeasure(
  893. element) : "Getting measurement for element that is not measured";
  894. return getMeasuredSize(element, nullSize).getOuterHeight();
  895. }
  896. /**
  897. * Gets the outer width (including margins, paddings and borders) of the
  898. * given element, provided that it has been measured. These elements are
  899. * guaranteed to be measured:
  900. * <ul>
  901. * <li>ManagedLayouts and their child Connectors
  902. * <li>Elements for which there is at least one ElementResizeListener
  903. * <li>Elements for which at least one ManagedLayout has registered a
  904. * dependency
  905. * </ul>
  906. *
  907. * -1 is returned if the element has not been measured. If 0 is returned, it
  908. * might indicate that the element is not attached to the DOM.
  909. * <p>
  910. * The value returned by this method is always rounded up. To get the exact
  911. * outer width, use {@link #getOuterWidthDouble(Element)}
  912. *
  913. * @since 7.5.1
  914. * @param element
  915. * the element to get the measured size for
  916. * @return the measured outer width (including margins, paddings and
  917. * borders) of the element in pixels.
  918. */
  919. public final int getOuterWidth(Element element) {
  920. assert needsMeasure(
  921. element) : "Getting measurement for element that is not measured";
  922. return (int) Math
  923. .ceil(getMeasuredSize(element, nullSize).getOuterWidth());
  924. }
  925. /**
  926. * Gets the outer width (including margins, paddings and borders) of the
  927. * given element, provided that it has been measured. These elements are
  928. * guaranteed to be measured:
  929. * <ul>
  930. * <li>ManagedLayouts and their child Connectors
  931. * <li>Elements for which there is at least one ElementResizeListener
  932. * <li>Elements for which at least one ManagedLayout has registered a
  933. * dependency
  934. * </ul>
  935. *
  936. * -1 is returned if the element has not been measured. If 0 is returned, it
  937. * might indicate that the element is not attached to the DOM.
  938. *
  939. * @param element
  940. * the element to get the measured size for
  941. * @return the measured outer width (including margins, paddings and
  942. * borders) of the element in pixels.
  943. */
  944. public final double getOuterWidthDouble(Element element) {
  945. assert needsMeasure(
  946. element) : "Getting measurement for element that is not measured";
  947. return getMeasuredSize(element, nullSize).getOuterWidth();
  948. }
  949. /**
  950. * Gets the inner height (excluding margins, paddings and borders) of the
  951. * given element, provided that it has been measured. These elements are
  952. * guaranteed to be measured:
  953. * <ul>
  954. * <li>ManagedLayouts and their child Connectors
  955. * <li>Elements for which there is at least one ElementResizeListener
  956. * <li>Elements for which at least one ManagedLayout has registered a
  957. * dependency
  958. * </ul>
  959. *
  960. * -1 is returned if the element has not been measured. If 0 is returned, it
  961. * might indicate that the element is not attached to the DOM.
  962. * <p>
  963. * The value returned by this method is always rounded up. To get the exact
  964. * outer width, use {@link #getInnerHeightDouble(Element)}
  965. *
  966. * @param element
  967. * the element to get the measured size for
  968. * @return the measured inner height (excluding margins, paddings and
  969. * borders) of the element in pixels.
  970. */
  971. public final int getInnerHeight(Element element) {
  972. assert needsMeasure(
  973. element) : "Getting measurement for element that is not measured";
  974. return (int) Math
  975. .ceil(getMeasuredSize(element, nullSize).getInnerHeight());
  976. }
  977. /**
  978. * Gets the inner height (excluding margins, paddings and borders) of the
  979. * given element, provided that it has been measured. These elements are
  980. * guaranteed to be measured:
  981. * <ul>
  982. * <li>ManagedLayouts and their child Connectors
  983. * <li>Elements for which there is at least one ElementResizeListener
  984. * <li>Elements for which at least one ManagedLayout has registered a
  985. * dependency
  986. * </ul>
  987. *
  988. * -1 is returned if the element has not been measured. If 0 is returned, it
  989. * might indicate that the element is not attached to the DOM.
  990. *
  991. * @since 7.5.1
  992. * @param element
  993. * the element to get the measured size for
  994. * @return the measured inner height (excluding margins, paddings and
  995. * borders) of the element in pixels.
  996. */
  997. public final double getInnerHeightDouble(Element element) {
  998. assert needsMeasure(
  999. element) : "Getting measurement for element that is not measured";
  1000. return getMeasuredSize(element, nullSize).getInnerHeight();
  1001. }
  1002. /**
  1003. * Gets the inner width (excluding margins, paddings and borders) of the
  1004. * given element, provided that it has been measured. These elements are
  1005. * guaranteed to be measured:
  1006. * <ul>
  1007. * <li>ManagedLayouts and their child Connectors
  1008. * <li>Elements for which there is at least one ElementResizeListener
  1009. * <li>Elements for which at least one ManagedLayout has registered a
  1010. * dependency
  1011. * </ul>
  1012. *
  1013. * -1 is returned if the element has not been measured. If 0 is returned, it
  1014. * might indicate that the element is not attached to the DOM.
  1015. * <p>
  1016. * The value returned by this method is always rounded up. To get the exact
  1017. * outer width, use {@link #getOuterHeightDouble(Element)}
  1018. *
  1019. * @param element
  1020. * the element to get the measured size for
  1021. * @return the measured inner width (excluding margins, paddings and
  1022. * borders) of the element in pixels.
  1023. */
  1024. public final int getInnerWidth(Element element) {
  1025. assert needsMeasure(
  1026. element) : "Getting measurement for element that is not measured";
  1027. return (int) Math
  1028. .ceil(getMeasuredSize(element, nullSize).getInnerWidth());
  1029. }
  1030. /**
  1031. * Gets the inner width (excluding margins, paddings and borders) of the
  1032. * given element, provided that it has been measured. These elements are
  1033. * guaranteed to be measured:
  1034. * <ul>
  1035. * <li>ManagedLayouts and their child Connectors
  1036. * <li>Elements for which there is at least one ElementResizeListener
  1037. * <li>Elements for which at least one ManagedLayout has registered a
  1038. * dependency
  1039. * </ul>
  1040. *
  1041. * -1 is returned if the element has not been measured. If 0 is returned, it
  1042. * might indicate that the element is not attached to the DOM.
  1043. *
  1044. * @since 7.5.1
  1045. * @param element
  1046. * the element to get the measured size for
  1047. * @return the measured inner width (excluding margins, paddings and
  1048. * borders) of the element in pixels.
  1049. */
  1050. public final double getInnerWidthDouble(Element element) {
  1051. assert needsMeasure(
  1052. element) : "Getting measurement for element that is not measured";
  1053. return getMeasuredSize(element, nullSize).getInnerWidth();
  1054. }
  1055. /**
  1056. * Gets the border height (top border + bottom border) of the given element,
  1057. * provided that it has been measured. These elements are guaranteed to be
  1058. * measured:
  1059. * <ul>
  1060. * <li>ManagedLayouts and their child Connectors
  1061. * <li>Elements for which there is at least one ElementResizeListener
  1062. * <li>Elements for which at least one ManagedLayout has registered a
  1063. * dependency
  1064. * </ul>
  1065. *
  1066. * A negative number is returned if the element has not been measured. If 0
  1067. * is returned, it might indicate that the element is not attached to the
  1068. * DOM.
  1069. *
  1070. * @param element
  1071. * the element to get the measured size for
  1072. * @return the measured border height (top border + bottom border) of the
  1073. * element in pixels.
  1074. */
  1075. public final int getBorderHeight(Element element) {
  1076. assert needsMeasure(
  1077. element) : "Getting measurement for element that is not measured";
  1078. return getMeasuredSize(element, nullSize).getBorderHeight();
  1079. }
  1080. /**
  1081. * Gets the padding height (top padding + bottom padding) of the given
  1082. * element, provided that it has been measured. These elements are
  1083. * guaranteed to be measured:
  1084. * <ul>
  1085. * <li>ManagedLayouts and their child Connectors
  1086. * <li>Elements for which there is at least one ElementResizeListener
  1087. * <li>Elements for which at least one ManagedLayout has registered a
  1088. * dependency
  1089. * </ul>
  1090. *
  1091. * A negative number is returned if the element has not been measured. If 0
  1092. * is returned, it might indicate that the element is not attached to the
  1093. * DOM.
  1094. *
  1095. * @param element
  1096. * the element to get the measured size for
  1097. * @return the measured padding height (top padding + bottom padding) of the
  1098. * element in pixels.
  1099. */
  1100. public int getPaddingHeight(Element element) {
  1101. assert needsMeasure(
  1102. element) : "Getting measurement for element that is not measured";
  1103. return getMeasuredSize(element, nullSize).getPaddingHeight();
  1104. }
  1105. /**
  1106. * Gets the border width (left border + right border) of the given element,
  1107. * provided that it has been measured. These elements are guaranteed to be
  1108. * measured:
  1109. * <ul>
  1110. * <li>ManagedLayouts and their child Connectors
  1111. * <li>Elements for which there is at least one ElementResizeListener
  1112. * <li>Elements for which at least one ManagedLayout has registered a
  1113. * dependency
  1114. * </ul>
  1115. *
  1116. * A negative number is returned if the element has not been measured. If 0
  1117. * is returned, it might indicate that the element is not attached to the
  1118. * DOM.
  1119. *
  1120. * @param element
  1121. * the element to get the measured size for
  1122. * @return the measured border width (left border + right border) of the
  1123. * element in pixels.
  1124. */
  1125. public int getBorderWidth(Element element) {
  1126. assert needsMeasure(
  1127. element) : "Getting measurement for element that is not measured";
  1128. return getMeasuredSize(element, nullSize).getBorderWidth();
  1129. }
  1130. /**
  1131. * Gets the top border of the given element, provided that it has been
  1132. * measured. These elements are guaranteed to be measured:
  1133. * <ul>
  1134. * <li>ManagedLayouts and their child Connectors
  1135. * <li>Elements for which there is at least one ElementResizeListener
  1136. * <li>Elements for which at least one ManagedLayout has registered a
  1137. * dependency
  1138. * </ul>
  1139. *
  1140. * A negative number is returned if the element has not been measured. If 0
  1141. * is returned, it might indicate that the element is not attached to the
  1142. * DOM.
  1143. *
  1144. * @param element
  1145. * the element to get the measured size for
  1146. * @return the measured top border of the element in pixels.
  1147. */
  1148. public int getBorderTop(Element element) {
  1149. assert needsMeasure(
  1150. element) : "Getting measurement for element that is not measured";
  1151. return getMeasuredSize(element, nullSize).getBorderTop();
  1152. }
  1153. /**
  1154. * Gets the left border of the given element, provided that it has been
  1155. * measured. These elements are guaranteed to be measured:
  1156. * <ul>
  1157. * <li>ManagedLayouts and their child Connectors
  1158. * <li>Elements for which there is at least one ElementResizeListener
  1159. * <li>Elements for which at least one ManagedLayout has registered a
  1160. * dependency
  1161. * </ul>
  1162. *
  1163. * A negative number is returned if the element has not been measured. If 0
  1164. * is returned, it might indicate that the element is not attached to the
  1165. * DOM.
  1166. *
  1167. * @param element
  1168. * the element to get the measured size for
  1169. * @return the measured left border of the element in pixels.
  1170. */
  1171. public int getBorderLeft(Element element) {
  1172. assert needsMeasure(
  1173. element) : "Getting measurement for element that is not measured";
  1174. return getMeasuredSize(element, nullSize).getBorderLeft();
  1175. }
  1176. /**
  1177. * Gets the bottom border of the given element, provided that it has been
  1178. * measured. These elements are guaranteed to be measured:
  1179. * <ul>
  1180. * <li>ManagedLayouts and their child Connectors
  1181. * <li>Elements for which there is at least one ElementResizeListener
  1182. * <li>Elements for which at least one ManagedLayout has registered a
  1183. * dependency
  1184. * </ul>
  1185. *
  1186. * A negative number is returned if the element has not been measured. If 0
  1187. * is returned, it might indicate that the element is not attached to the
  1188. * DOM.
  1189. *
  1190. * @param element
  1191. * the element to get the measured size for
  1192. * @return the measured bottom border of the element in pixels.
  1193. */
  1194. public int getBorderBottom(Element element) {
  1195. assert needsMeasure(
  1196. element) : "Getting measurement for element that is not measured";
  1197. return getMeasuredSize(element, nullSize).getBorderBottom();
  1198. }
  1199. /**
  1200. * Gets the right border of the given element, provided that it has been
  1201. * measured. These elements are guaranteed to be measured:
  1202. * <ul>
  1203. * <li>ManagedLayouts and their child Connectors
  1204. * <li>Elements for which there is at least one ElementResizeListener
  1205. * <li>Elements for which at least one ManagedLayout has registered a
  1206. * dependency
  1207. * </ul>
  1208. *
  1209. * A negative number is returned if the element has not been measured. If 0
  1210. * is returned, it might indicate that the element is not attached to the
  1211. * DOM.
  1212. *
  1213. * @param element
  1214. * the element to get the measured size for
  1215. * @return the measured right border of the element in pixels.
  1216. */
  1217. public int getBorderRight(Element element) {
  1218. assert needsMeasure(
  1219. element) : "Getting measurement for element that is not measured";
  1220. return getMeasuredSize(element, nullSize).getBorderRight();
  1221. }
  1222. /**
  1223. * Gets the padding width (left padding + right padding) of the given
  1224. * element, provided that it has been measured. These elements are
  1225. * guaranteed to be measured:
  1226. * <ul>
  1227. * <li>ManagedLayouts and their child Connectors
  1228. * <li>Elements for which there is at least one ElementResizeListener
  1229. * <li>Elements for which at least one ManagedLayout has registered a
  1230. * dependency
  1231. * </ul>
  1232. *
  1233. * A negative number is returned if the element has not been measured. If 0
  1234. * is returned, it might indicate that the element is not attached to the
  1235. * DOM.
  1236. *
  1237. * @param element
  1238. * the element to get the measured size for
  1239. * @return the measured padding width (left padding + right padding) of the
  1240. * element in pixels.
  1241. */
  1242. public int getPaddingWidth(Element element) {
  1243. assert needsMeasure(
  1244. element) : "Getting measurement for element that is not measured";
  1245. return getMeasuredSize(element, nullSize).getPaddingWidth();
  1246. }
  1247. /**
  1248. * Gets the top padding of the given element, provided that it has been
  1249. * measured. These elements are guaranteed to be measured:
  1250. * <ul>
  1251. * <li>ManagedLayouts and their child Connectors
  1252. * <li>Elements for which there is at least one ElementResizeListener
  1253. * <li>Elements for which at least one ManagedLayout has registered a
  1254. * dependency
  1255. * </ul>
  1256. *
  1257. * A negative number is returned if the element has not been measured. If 0
  1258. * is returned, it might indicate that the element is not attached to the
  1259. * DOM.
  1260. *
  1261. * @param element
  1262. * the element to get the measured size for
  1263. * @return the measured top padding of the element in pixels.
  1264. */
  1265. public int getPaddingTop(Element element) {
  1266. assert needsMeasure(
  1267. element) : "Getting measurement for element that is not measured";
  1268. return getMeasuredSize(element, nullSize).getPaddingTop();
  1269. }
  1270. /**
  1271. * Gets the left padding of the given element, provided that it has been
  1272. * measured. These elements are guaranteed to be measured:
  1273. * <ul>
  1274. * <li>ManagedLayouts and their child Connectors
  1275. * <li>Elements for which there is at least one ElementResizeListener
  1276. * <li>Elements for which at least one ManagedLayout has registered a
  1277. * dependency
  1278. * </ul>
  1279. *
  1280. * A negative number is returned if the element has not been measured. If 0
  1281. * is returned, it might indicate that the element is not attached to the
  1282. * DOM.
  1283. *
  1284. * @param element
  1285. * the element to get the measured size for
  1286. * @return the measured left padding of the element in pixels.
  1287. */
  1288. public int getPaddingLeft(Element element) {
  1289. assert needsMeasure(
  1290. element) : "Getting measurement for element that is not measured";
  1291. return getMeasuredSize(element, nullSize).getPaddingLeft();
  1292. }
  1293. /**
  1294. * Gets the bottom padding of the given element, provided that it has been
  1295. * measured. These elements are guaranteed to be measured:
  1296. * <ul>
  1297. * <li>ManagedLayouts and their child Connectors
  1298. * <li>Elements for which there is at least one ElementResizeListener
  1299. * <li>Elements for which at least one ManagedLayout has registered a
  1300. * dependency
  1301. * </ul>
  1302. *
  1303. * A negative number is returned if the element has not been measured. If 0
  1304. * is returned, it might indicate that the element is not attached to the
  1305. * DOM.
  1306. *
  1307. * @param element
  1308. * the element to get the measured size for
  1309. * @return the measured bottom padding of the element in pixels.
  1310. */
  1311. public int getPaddingBottom(Element element) {
  1312. assert needsMeasure(
  1313. element) : "Getting measurement for element that is not measured";
  1314. return getMeasuredSize(element, nullSize).getPaddingBottom();
  1315. }
  1316. /**
  1317. * Gets the right padding of the given element, provided that it has been
  1318. * measured. These elements are guaranteed to be measured:
  1319. * <ul>
  1320. * <li>ManagedLayouts and their child Connectors
  1321. * <li>Elements for which there is at least one ElementResizeListener
  1322. * <li>Elements for which at least one ManagedLayout has registered a
  1323. * dependency
  1324. * </ul>
  1325. *
  1326. * A negative number is returned if the element has not been measured. If 0
  1327. * is returned, it might indicate that the element is not attached to the
  1328. * DOM.
  1329. *
  1330. * @param element
  1331. * the element to get the measured size for
  1332. * @return the measured right padding of the element in pixels.
  1333. */
  1334. public int getPaddingRight(Element element) {
  1335. assert needsMeasure(
  1336. element) : "Getting measurement for element that is not measured";
  1337. return getMeasuredSize(element, nullSize).getPaddingRight();
  1338. }
  1339. /**
  1340. * Gets the top margin of the given element, provided that it has been
  1341. * measured. These elements are guaranteed to be measured:
  1342. * <ul>
  1343. * <li>ManagedLayouts and their child Connectors
  1344. * <li>Elements for which there is at least one ElementResizeListener
  1345. * <li>Elements for which at least one ManagedLayout has registered a
  1346. * dependency
  1347. * </ul>
  1348. *
  1349. * A negative number is returned if the element has not been measured. If 0
  1350. * is returned, it might indicate that the element is not attached to the
  1351. * DOM.
  1352. *
  1353. * @param element
  1354. * the element to get the measured size for
  1355. * @return the measured top margin of the element in pixels.
  1356. */
  1357. public int getMarginTop(Element element) {
  1358. assert needsMeasure(
  1359. element) : "Getting measurement for element that is not measured";
  1360. return getMeasuredSize(element, nullSize).getMarginTop();
  1361. }
  1362. /**
  1363. * Gets the right margin of the given element, provided that it has been
  1364. * measured. These elements are guaranteed to be measured:
  1365. * <ul>
  1366. * <li>ManagedLayouts and their child Connectors
  1367. * <li>Elements for which there is at least one ElementResizeListener
  1368. * <li>Elements for which at least one ManagedLayout has registered a
  1369. * dependency
  1370. * </ul>
  1371. *
  1372. * A negative number is returned if the element has not been measured. If 0
  1373. * is returned, it might indicate that the element is not attached to the
  1374. * DOM.
  1375. *
  1376. * @param element
  1377. * the element to get the measured size for
  1378. * @return the measured right margin of the element in pixels.
  1379. */
  1380. public int getMarginRight(Element element) {
  1381. assert needsMeasure(
  1382. element) : "Getting measurement for element that is not measured";
  1383. return getMeasuredSize(element, nullSize).getMarginRight();
  1384. }
  1385. /**
  1386. * Gets the bottom margin of the given element, provided that it has been
  1387. * measured. These elements are guaranteed to be measured:
  1388. * <ul>
  1389. * <li>ManagedLayouts and their child Connectors
  1390. * <li>Elements for which there is at least one ElementResizeListener
  1391. * <li>Elements for which at least one ManagedLayout has registered a
  1392. * dependency
  1393. * </ul>
  1394. *
  1395. * A negative number is returned if the element has not been measured. If 0
  1396. * is returned, it might indicate that the element is not attached to the
  1397. * DOM.
  1398. *
  1399. * @param element
  1400. * the element to get the measured size for
  1401. * @return the measured bottom margin of the element in pixels.
  1402. */
  1403. public int getMarginBottom(Element element) {
  1404. assert needsMeasure(
  1405. element) : "Getting measurement for element that is not measured";
  1406. return getMeasuredSize(element, nullSize).getMarginBottom();
  1407. }
  1408. /**
  1409. * Gets the left margin of the given element, provided that it has been
  1410. * measured. These elements are guaranteed to be measured:
  1411. * <ul>
  1412. * <li>ManagedLayouts and their child Connectors
  1413. * <li>Elements for which there is at least one ElementResizeListener
  1414. * <li>Elements for which at least one ManagedLayout has registered a
  1415. * dependency
  1416. * </ul>
  1417. *
  1418. * A negative number is returned if the element has not been measured. If 0
  1419. * is returned, it might indicate that the element is not attached to the
  1420. * DOM.
  1421. *
  1422. * @param element
  1423. * the element to get the measured size for
  1424. * @return the measured left margin of the element in pixels.
  1425. */
  1426. public int getMarginLeft(Element element) {
  1427. assert needsMeasure(
  1428. element) : "Getting measurement for element that is not measured";
  1429. return getMeasuredSize(element, nullSize).getMarginLeft();
  1430. }
  1431. /**
  1432. * Gets the combined top & bottom margin of the given element, provided that
  1433. * they have been measured. These elements are guaranteed to be measured:
  1434. * <ul>
  1435. * <li>ManagedLayouts and their child Connectors
  1436. * <li>Elements for which there is at least one ElementResizeListener
  1437. * <li>Elements for which at least one ManagedLayout has registered a
  1438. * dependency
  1439. * </ul>
  1440. *
  1441. * A negative number is returned if the element has not been measured. If 0
  1442. * is returned, it might indicate that the element is not attached to the
  1443. * DOM.
  1444. *
  1445. * @param element
  1446. * the element to get the measured margin for
  1447. * @return the measured top+bottom margin of the element in pixels.
  1448. */
  1449. public int getMarginHeight(Element element) {
  1450. return getMarginTop(element) + getMarginBottom(element);
  1451. }
  1452. /**
  1453. * Gets the combined left & right margin of the given element, provided that
  1454. * they have been measured. These elements are guaranteed to be measured:
  1455. * <ul>
  1456. * <li>ManagedLayouts and their child Connectors
  1457. * <li>Elements for which there is at least one ElementResizeListener
  1458. * <li>Elements for which at least one ManagedLayout has registered a
  1459. * dependency
  1460. * </ul>
  1461. *
  1462. * A negative number is returned if the element has not been measured. If 0
  1463. * is returned, it might indicate that the element is not attached to the
  1464. * DOM.
  1465. *
  1466. * @param element
  1467. * the element to get the measured margin for
  1468. * @return the measured left+right margin of the element in pixels.
  1469. */
  1470. public int getMarginWidth(Element element) {
  1471. return getMarginLeft(element) + getMarginRight(element);
  1472. }
  1473. /**
  1474. * Registers the outer height (including margins, borders and paddings) of a
  1475. * component. This can be used as an optimization by ManagedLayouts; by
  1476. * informing the LayoutManager about what size a component will have, the
  1477. * layout propagation can continue directly without first measuring the
  1478. * potentially resized elements.
  1479. *
  1480. * @param component
  1481. * the component for which the size is reported
  1482. * @param outerHeight
  1483. * the new outer height (including margins, borders and paddings)
  1484. * of the component in pixels
  1485. */
  1486. public void reportOuterHeight(ComponentConnector component,
  1487. int outerHeight) {
  1488. Element element = component.getWidget().getElement();
  1489. MeasuredSize measuredSize = getMeasuredSize(element);
  1490. if (isLayoutRunning()) {
  1491. boolean heightChanged = measuredSize.setOuterHeight(outerHeight);
  1492. if (heightChanged) {
  1493. onConnectorChange(component, false, true);
  1494. notifyListenersAndDepdendents(element, false, true);
  1495. }
  1496. currentDependencyTree.setNeedsVerticalMeasure(component, false);
  1497. } else if (measuredSize.getOuterHeight() != outerHeight) {
  1498. setNeedsMeasure(component);
  1499. }
  1500. }
  1501. /**
  1502. * Registers the height reserved for a relatively sized component. This can
  1503. * be used as an optimization by ManagedLayouts; by informing the
  1504. * LayoutManager about what size a component will have, the layout
  1505. * propagation can continue directly without first measuring the potentially
  1506. * resized elements.
  1507. *
  1508. * @param component
  1509. * the relatively sized component for which the size is reported
  1510. * @param assignedHeight
  1511. * the inner height of the relatively sized component's parent
  1512. * element in pixels
  1513. */
  1514. public void reportHeightAssignedToRelative(ComponentConnector component,
  1515. int assignedHeight) {
  1516. assert component.isRelativeHeight();
  1517. float percentSize = parsePercent(component.getState().height == null
  1518. ? "" : component.getState().height);
  1519. int effectiveHeight = Math.round(assignedHeight * (percentSize / 100));
  1520. reportOuterHeight(component, effectiveHeight);
  1521. }
  1522. /**
  1523. * Registers the width reserved for a relatively sized component. This can
  1524. * be used as an optimization by ManagedLayouts; by informing the
  1525. * LayoutManager about what size a component will have, the layout
  1526. * propagation can continue directly without first measuring the potentially
  1527. * resized elements.
  1528. *
  1529. * @param component
  1530. * the relatively sized component for which the size is reported
  1531. * @param assignedWidth
  1532. * the inner width of the relatively sized component's parent
  1533. * element in pixels
  1534. */
  1535. public void reportWidthAssignedToRelative(ComponentConnector component,
  1536. int assignedWidth) {
  1537. assert component.isRelativeWidth();
  1538. float percentSize = parsePercent(component.getState().width == null ? ""
  1539. : component.getState().width);
  1540. int effectiveWidth = Math.round(assignedWidth * (percentSize / 100));
  1541. reportOuterWidth(component, effectiveWidth);
  1542. }
  1543. private static float parsePercent(String size) {
  1544. return Float.parseFloat(size.substring(0, size.length() - 1));
  1545. }
  1546. /**
  1547. * Registers the outer width (including margins, borders and paddings) of a
  1548. * component. This can be used as an optimization by ManagedLayouts; by
  1549. * informing the LayoutManager about what size a component will have, the
  1550. * layout propagation can continue directly without first measuring the
  1551. * potentially resized elements.
  1552. *
  1553. * @param component
  1554. * the component for which the size is reported
  1555. * @param outerWidth
  1556. * the new outer width (including margins, borders and paddings)
  1557. * of the component in pixels
  1558. */
  1559. public void reportOuterWidth(ComponentConnector component, int outerWidth) {
  1560. Element element = component.getWidget().getElement();
  1561. MeasuredSize measuredSize = getMeasuredSize(element);
  1562. if (isLayoutRunning()) {
  1563. boolean widthChanged = measuredSize.setOuterWidth(outerWidth);
  1564. if (widthChanged) {
  1565. onConnectorChange(component, true, false);
  1566. notifyListenersAndDepdendents(element, true, false);
  1567. }
  1568. currentDependencyTree.setNeedsHorizontalMeasure(component, false);
  1569. } else if (measuredSize.getOuterWidth() != outerWidth) {
  1570. setNeedsMeasure(component);
  1571. }
  1572. }
  1573. /**
  1574. * Adds a listener that will be notified whenever the size of a specific
  1575. * element changes. Adding a listener to an element also ensures that all
  1576. * sizes for that element will be available starting from the next layout
  1577. * phase.
  1578. *
  1579. * @param element
  1580. * the element that should be checked for size changes
  1581. * @param listener
  1582. * an ElementResizeListener that will be informed whenever the
  1583. * size of the target element has changed
  1584. */
  1585. public void addElementResizeListener(Element element,
  1586. ElementResizeListener listener) {
  1587. Collection<ElementResizeListener> listeners = elementResizeListeners
  1588. .get(element);
  1589. if (listeners == null) {
  1590. listeners = new HashSet<ElementResizeListener>();
  1591. elementResizeListeners.put(element, listeners);
  1592. ensureMeasured(element);
  1593. }
  1594. listeners.add(listener);
  1595. }
  1596. /**
  1597. * Removes an element resize listener from the provided element. This might
  1598. * cause this LayoutManager to stop tracking the size of the element if no
  1599. * other sources are interested in the size.
  1600. *
  1601. * @param element
  1602. * the element to which the element resize listener was
  1603. * previously added
  1604. * @param listener
  1605. * the ElementResizeListener that should no longer get informed
  1606. * about size changes to the target element.
  1607. */
  1608. public void removeElementResizeListener(Element element,
  1609. ElementResizeListener listener) {
  1610. Collection<ElementResizeListener> listeners = elementResizeListeners
  1611. .get(element);
  1612. if (listeners != null) {
  1613. listeners.remove(listener);
  1614. if (listeners.isEmpty()) {
  1615. elementResizeListeners.remove(element);
  1616. stopMeasuringIfUnecessary(element);
  1617. }
  1618. }
  1619. }
  1620. private void stopMeasuringIfUnecessary(Element element) {
  1621. if (!needsMeasure(element)) {
  1622. measuredNonConnectorElements.remove(element);
  1623. setMeasuredSize(element, null);
  1624. }
  1625. }
  1626. /**
  1627. * Informs this LayoutManager that the size of a component might have
  1628. * changed. This method should be used whenever the size of an individual
  1629. * component might have changed from outside of Vaadin's normal update
  1630. * phase, e.g. when an icon has been loaded or when the user resizes some
  1631. * part of the UI using the mouse.
  1632. * <p>
  1633. * To set an entire component hierarchy to be measured, use
  1634. * {@link #setNeedsMeasureRecursively(ComponentConnector)} instead.
  1635. * <p>
  1636. * If there is no upcoming layout phase, a new layout phase is scheduled.
  1637. *
  1638. * @param component
  1639. * the component whose size might have changed.
  1640. */
  1641. public void setNeedsMeasure(ComponentConnector component) {
  1642. if (isLayoutRunning()) {
  1643. currentDependencyTree.setNeedsMeasure(component, true);
  1644. } else {
  1645. needsMeasure.add(component.getConnectorId());
  1646. layoutLater();
  1647. }
  1648. }
  1649. /**
  1650. * Informs this LayoutManager that some sizes in a component hierarchy might
  1651. * have changed. This method should be used whenever the size of any child
  1652. * component might have changed from outside of Vaadin's normal update
  1653. * phase, e.g. when a CSS class name related to sizing has been changed.
  1654. * <p>
  1655. * To set a single component to be measured, use
  1656. * {@link #setNeedsMeasure(ComponentConnector)} instead.
  1657. * <p>
  1658. * If there is no upcoming layout phase, a new layout phase is scheduled.
  1659. *
  1660. * @since 7.2
  1661. * @param component
  1662. * the component at the root of the component hierarchy to
  1663. * measure
  1664. */
  1665. public void setNeedsMeasureRecursively(ComponentConnector component) {
  1666. setNeedsMeasure(component);
  1667. if (component instanceof HasComponentsConnector) {
  1668. HasComponentsConnector hasComponents = (HasComponentsConnector) component;
  1669. for (ComponentConnector child : hasComponents
  1670. .getChildComponents()) {
  1671. setNeedsMeasureRecursively(child);
  1672. }
  1673. }
  1674. }
  1675. public void setEverythingNeedsMeasure() {
  1676. everythingNeedsMeasure = true;
  1677. }
  1678. /**
  1679. * Clean measured sizes which are no longer needed. Only for IE8.
  1680. */
  1681. public void cleanMeasuredSizes() {
  1682. }
  1683. private static Logger getLogger() {
  1684. return Logger.getLogger(LayoutManager.class.getName());
  1685. }
  1686. /**
  1687. * Checks if there is something waiting for a layout to take place.
  1688. *
  1689. * @since 7.5.6
  1690. * @return true if there are connectors waiting for measurement or layout,
  1691. * false otherwise
  1692. */
  1693. public boolean isLayoutNeeded() {
  1694. if (!needsHorizontalLayout.isEmpty()
  1695. || !needsVerticalLayout.isEmpty()) {
  1696. return true;
  1697. }
  1698. if (!needsMeasure.isEmpty()) {
  1699. return true;
  1700. }
  1701. if (everythingNeedsMeasure) {
  1702. return true;
  1703. }
  1704. return false;
  1705. }
  1706. }