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 50KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276
  1. /*
  2. * Copyright 2011 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 com.google.gwt.core.client.Duration;
  23. import com.google.gwt.core.client.JsArrayString;
  24. import com.google.gwt.dom.client.Element;
  25. import com.google.gwt.dom.client.Style;
  26. import com.google.gwt.dom.client.Style.Overflow;
  27. import com.google.gwt.user.client.Timer;
  28. import com.vaadin.client.MeasuredSize.MeasureResult;
  29. import com.vaadin.client.ui.ManagedLayout;
  30. import com.vaadin.client.ui.PostLayoutListener;
  31. import com.vaadin.client.ui.SimpleManagedLayout;
  32. import com.vaadin.client.ui.layout.ElementResizeEvent;
  33. import com.vaadin.client.ui.layout.ElementResizeListener;
  34. import com.vaadin.client.ui.layout.LayoutDependencyTree;
  35. import com.vaadin.client.ui.notification.VNotification;
  36. public class LayoutManager {
  37. private static final String LOOP_ABORT_MESSAGE = "Aborting layout after 100 passes. This would probably be an infinite loop.";
  38. private static final boolean debugLogging = false;
  39. private ApplicationConnection connection;
  40. private final Set<Element> measuredNonConnectorElements = new HashSet<Element>();
  41. private final MeasuredSize nullSize = new MeasuredSize();
  42. private LayoutDependencyTree currentDependencyTree;
  43. private final Collection<ManagedLayout> needsHorizontalLayout = new HashSet<ManagedLayout>();
  44. private final Collection<ManagedLayout> needsVerticalLayout = new HashSet<ManagedLayout>();
  45. private final Collection<ComponentConnector> needsMeasure = new HashSet<ComponentConnector>();
  46. private Collection<ComponentConnector> pendingOverflowFixes = new HashSet<ComponentConnector>();
  47. private final Map<Element, Collection<ElementResizeListener>> elementResizeListeners = new HashMap<Element, Collection<ElementResizeListener>>();
  48. private final Set<Element> listenersToFire = new HashSet<Element>();
  49. private boolean layoutPending = false;
  50. private Timer layoutTimer = new Timer() {
  51. @Override
  52. public void run() {
  53. cancel();
  54. layoutNow();
  55. }
  56. };
  57. private boolean everythingNeedsMeasure = false;
  58. public void setConnection(ApplicationConnection connection) {
  59. if (this.connection != null) {
  60. throw new RuntimeException(
  61. "LayoutManager connection can never be changed");
  62. }
  63. this.connection = connection;
  64. }
  65. /**
  66. * Gets the layout manager associated with the given
  67. * {@link ApplicationConnection}.
  68. *
  69. * @param connection
  70. * the application connection to get a layout manager for
  71. * @return the layout manager associated with the provided application
  72. * connection
  73. */
  74. public static LayoutManager get(ApplicationConnection connection) {
  75. return connection.getLayoutManager();
  76. }
  77. /**
  78. * Registers that a ManagedLayout is depending on the size of an Element.
  79. * This causes this layout manager to measure the element in the beginning
  80. * of every layout phase and call the appropriate layout method of the
  81. * managed layout if the size of the element has changed.
  82. *
  83. * @param owner
  84. * the ManagedLayout that depends on an element
  85. * @param element
  86. * the Element that should be measured
  87. */
  88. public void registerDependency(ManagedLayout owner, Element element) {
  89. MeasuredSize measuredSize = ensureMeasured(element);
  90. setNeedsLayout(owner);
  91. measuredSize.addDependent(owner.getConnectorId());
  92. }
  93. private MeasuredSize ensureMeasured(Element element) {
  94. MeasuredSize measuredSize = getMeasuredSize(element, null);
  95. if (measuredSize == null) {
  96. measuredSize = new MeasuredSize();
  97. if (ConnectorMap.get(connection).getConnector(element) == null) {
  98. measuredNonConnectorElements.add(element);
  99. }
  100. setMeasuredSize(element, measuredSize);
  101. }
  102. return measuredSize;
  103. }
  104. private boolean needsMeasure(Element e) {
  105. if (connection.getConnectorMap().getConnectorId(e) != null) {
  106. return true;
  107. } else if (elementResizeListeners.containsKey(e)) {
  108. return true;
  109. } else if (getMeasuredSize(e, nullSize).hasDependents()) {
  110. return true;
  111. } else {
  112. return false;
  113. }
  114. }
  115. /**
  116. * Assigns a measured size to an element. Method defined as protected to
  117. * allow separate implementation for IE8.
  118. *
  119. * @param element
  120. * the dom element to attach the measured size to
  121. * @param measuredSize
  122. * the measured size to attach to the element. If
  123. * <code>null</code>, any previous measured size is removed.
  124. */
  125. protected native void setMeasuredSize(Element element,
  126. MeasuredSize measuredSize)
  127. /*-{
  128. if (measuredSize) {
  129. element.vMeasuredSize = measuredSize;
  130. } else {
  131. delete element.vMeasuredSize;
  132. }
  133. }-*/;
  134. /**
  135. * Gets the measured size for an element. Method defined as protected to
  136. * allow separate implementation for IE8.
  137. *
  138. * @param element
  139. * The element to get measured size for
  140. * @param defaultSize
  141. * The size to return if no measured size could be found
  142. * @return The measured size for the element or {@literal defaultSize}
  143. */
  144. protected native MeasuredSize getMeasuredSize(Element element,
  145. MeasuredSize defaultSize)
  146. /*-{
  147. return element.vMeasuredSize || defaultSize;
  148. }-*/;
  149. private final MeasuredSize getMeasuredSize(ComponentConnector connector) {
  150. Element element = connector.getWidget().getElement();
  151. MeasuredSize measuredSize = getMeasuredSize(element, null);
  152. if (measuredSize == null) {
  153. measuredSize = new MeasuredSize();
  154. setMeasuredSize(element, measuredSize);
  155. }
  156. return measuredSize;
  157. }
  158. /**
  159. * Registers that a ManagedLayout is no longer depending on the size of an
  160. * Element.
  161. *
  162. * @see #registerDependency(ManagedLayout, Element)
  163. *
  164. * @param owner
  165. * the ManagedLayout no longer depends on an element
  166. * @param element
  167. * the Element that that no longer needs to be measured
  168. */
  169. public void unregisterDependency(ManagedLayout owner, Element element) {
  170. MeasuredSize measuredSize = getMeasuredSize(element, null);
  171. if (measuredSize == null) {
  172. return;
  173. }
  174. measuredSize.removeDependent(owner.getConnectorId());
  175. stopMeasuringIfUnecessary(element);
  176. }
  177. public boolean isLayoutRunning() {
  178. return currentDependencyTree != null;
  179. }
  180. private void countLayout(Map<ManagedLayout, Integer> layoutCounts,
  181. ManagedLayout layout) {
  182. Integer count = layoutCounts.get(layout);
  183. if (count == null) {
  184. count = Integer.valueOf(0);
  185. } else {
  186. count = Integer.valueOf(count.intValue() + 1);
  187. }
  188. layoutCounts.put(layout, count);
  189. if (count.intValue() > 2) {
  190. VConsole.error(Util.getConnectorString(layout)
  191. + " has been layouted " + count.intValue() + " times");
  192. }
  193. }
  194. public void layoutLater() {
  195. if (!layoutPending) {
  196. layoutPending = true;
  197. layoutTimer.schedule(100);
  198. }
  199. }
  200. public void layoutNow() {
  201. if (isLayoutRunning()) {
  202. throw new IllegalStateException(
  203. "Can't start a new layout phase before the previous layout phase ends.");
  204. }
  205. layoutPending = false;
  206. try {
  207. currentDependencyTree = new LayoutDependencyTree();
  208. doLayout();
  209. } finally {
  210. currentDependencyTree = null;
  211. }
  212. }
  213. private void doLayout() {
  214. VConsole.log("Starting layout phase");
  215. Map<ManagedLayout, Integer> layoutCounts = new HashMap<ManagedLayout, Integer>();
  216. int passes = 0;
  217. Duration totalDuration = new Duration();
  218. for (ManagedLayout layout : needsHorizontalLayout) {
  219. currentDependencyTree.setNeedsHorizontalLayout(layout, true);
  220. }
  221. for (ManagedLayout layout : needsVerticalLayout) {
  222. currentDependencyTree.setNeedsVerticalLayout(layout, true);
  223. }
  224. needsHorizontalLayout.clear();
  225. needsVerticalLayout.clear();
  226. for (ComponentConnector connector : needsMeasure) {
  227. currentDependencyTree.setNeedsMeasure(connector, true);
  228. }
  229. needsMeasure.clear();
  230. measureNonConnectors();
  231. VConsole.log("Layout init in " + totalDuration.elapsedMillis() + " ms");
  232. while (true) {
  233. Duration passDuration = new Duration();
  234. passes++;
  235. int measuredConnectorCount = measureConnectors(
  236. currentDependencyTree, everythingNeedsMeasure);
  237. everythingNeedsMeasure = false;
  238. if (measuredConnectorCount == 0) {
  239. VConsole.log("No more changes in pass " + passes);
  240. break;
  241. }
  242. int measureTime = passDuration.elapsedMillis();
  243. VConsole.log(" Measured " + measuredConnectorCount
  244. + " elements in " + measureTime + " ms");
  245. if (!listenersToFire.isEmpty()) {
  246. for (Element element : listenersToFire) {
  247. Collection<ElementResizeListener> listeners = elementResizeListeners
  248. .get(element);
  249. if (listeners != null) {
  250. ElementResizeListener[] array = listeners
  251. .toArray(new ElementResizeListener[listeners
  252. .size()]);
  253. ElementResizeEvent event = new ElementResizeEvent(this,
  254. element);
  255. for (ElementResizeListener listener : array) {
  256. try {
  257. listener.onElementResize(event);
  258. } catch (RuntimeException e) {
  259. VConsole.error(e);
  260. }
  261. }
  262. }
  263. }
  264. int measureListenerTime = passDuration.elapsedMillis();
  265. VConsole.log(" Fired resize listeners for "
  266. + listenersToFire.size() + " elements in "
  267. + (measureListenerTime - measureTime) + " ms");
  268. measureTime = measuredConnectorCount;
  269. listenersToFire.clear();
  270. }
  271. FastStringSet updatedSet = FastStringSet.create();
  272. while (currentDependencyTree.hasHorizontalConnectorToLayout()
  273. || currentDependencyTree.hasVerticaConnectorToLayout()) {
  274. for (ManagedLayout layout : currentDependencyTree
  275. .getHorizontalLayoutTargets()) {
  276. if (layout instanceof DirectionalManagedLayout) {
  277. currentDependencyTree
  278. .markAsHorizontallyLayouted(layout);
  279. DirectionalManagedLayout cl = (DirectionalManagedLayout) layout;
  280. try {
  281. cl.layoutHorizontally();
  282. } catch (RuntimeException e) {
  283. VConsole.error(e);
  284. }
  285. countLayout(layoutCounts, cl);
  286. } else {
  287. currentDependencyTree
  288. .markAsHorizontallyLayouted(layout);
  289. currentDependencyTree.markAsVerticallyLayouted(layout);
  290. SimpleManagedLayout rr = (SimpleManagedLayout) layout;
  291. try {
  292. rr.layout();
  293. } catch (RuntimeException e) {
  294. VConsole.error(e);
  295. }
  296. countLayout(layoutCounts, rr);
  297. }
  298. if (debugLogging) {
  299. updatedSet.add(layout.getConnectorId());
  300. }
  301. }
  302. for (ManagedLayout layout : currentDependencyTree
  303. .getVerticalLayoutTargets()) {
  304. if (layout instanceof DirectionalManagedLayout) {
  305. currentDependencyTree.markAsVerticallyLayouted(layout);
  306. DirectionalManagedLayout cl = (DirectionalManagedLayout) layout;
  307. try {
  308. cl.layoutVertically();
  309. } catch (RuntimeException e) {
  310. VConsole.error(e);
  311. }
  312. countLayout(layoutCounts, cl);
  313. } else {
  314. currentDependencyTree
  315. .markAsHorizontallyLayouted(layout);
  316. currentDependencyTree.markAsVerticallyLayouted(layout);
  317. SimpleManagedLayout rr = (SimpleManagedLayout) layout;
  318. try {
  319. rr.layout();
  320. } catch (RuntimeException e) {
  321. VConsole.error(e);
  322. }
  323. countLayout(layoutCounts, rr);
  324. }
  325. if (debugLogging) {
  326. updatedSet.add(layout.getConnectorId());
  327. }
  328. }
  329. }
  330. if (debugLogging) {
  331. JsArrayString changedCids = updatedSet.dump();
  332. StringBuilder b = new StringBuilder(" ");
  333. b.append(changedCids.length());
  334. b.append(" requestLayout invocations in ");
  335. b.append(passDuration.elapsedMillis() - measureTime);
  336. b.append(" ms");
  337. if (changedCids.length() < 30) {
  338. for (int i = 0; i < changedCids.length(); i++) {
  339. if (i != 0) {
  340. b.append(", ");
  341. } else {
  342. b.append(": ");
  343. }
  344. String connectorString = changedCids.get(i);
  345. if (changedCids.length() < 10) {
  346. ServerConnector connector = ConnectorMap.get(
  347. connection).getConnector(connectorString);
  348. connectorString = Util
  349. .getConnectorString(connector);
  350. }
  351. b.append(connectorString);
  352. }
  353. }
  354. VConsole.log(b.toString());
  355. }
  356. VConsole.log("Pass " + passes + " completed in "
  357. + passDuration.elapsedMillis() + " ms");
  358. if (passes > 100) {
  359. VConsole.log(LOOP_ABORT_MESSAGE);
  360. VNotification.createNotification(VNotification.DELAY_FOREVER,
  361. connection.getUIConnector().getWidget()).show(
  362. LOOP_ABORT_MESSAGE, VNotification.CENTERED, "error");
  363. break;
  364. }
  365. }
  366. int postLayoutStart = totalDuration.elapsedMillis();
  367. for (ComponentConnector connector : connection.getConnectorMap()
  368. .getComponentConnectors()) {
  369. if (connector instanceof PostLayoutListener) {
  370. ((PostLayoutListener) connector).postLayout();
  371. }
  372. }
  373. int postLayoutDone = (totalDuration.elapsedMillis() - postLayoutStart);
  374. VConsole.log("Invoke post layout listeners in " + postLayoutDone
  375. + " ms");
  376. cleanMeasuredSizes();
  377. int cleaningDone = (totalDuration.elapsedMillis() - postLayoutDone);
  378. VConsole.log("Cleaned old measured sizes in " + cleaningDone + "ms");
  379. VConsole.log("Total layout phase time: "
  380. + totalDuration.elapsedMillis() + "ms");
  381. }
  382. private void logConnectorStatus(int connectorId) {
  383. currentDependencyTree
  384. .logDependencyStatus((ComponentConnector) ConnectorMap.get(
  385. connection).getConnector(Integer.toString(connectorId)));
  386. }
  387. private int measureConnectors(LayoutDependencyTree layoutDependencyTree,
  388. boolean measureAll) {
  389. if (!pendingOverflowFixes.isEmpty()) {
  390. Duration duration = new Duration();
  391. HashMap<Element, String> originalOverflows = new HashMap<Element, String>();
  392. HashSet<ComponentConnector> delayedOverflowFixes = new HashSet<ComponentConnector>();
  393. // First set overflow to hidden (and save previous value so it can
  394. // be restored later)
  395. for (ComponentConnector componentConnector : pendingOverflowFixes) {
  396. // Delay the overflow fix if the involved connectors might still
  397. // change
  398. boolean connectorChangesExpected = !currentDependencyTree
  399. .noMoreChangesExpected(componentConnector);
  400. boolean parentChangesExcpected = componentConnector.getParent() instanceof ComponentConnector
  401. && !currentDependencyTree
  402. .noMoreChangesExpected((ComponentConnector) componentConnector
  403. .getParent());
  404. if (connectorChangesExpected || parentChangesExcpected) {
  405. delayedOverflowFixes.add(componentConnector);
  406. continue;
  407. }
  408. if (debugLogging) {
  409. VConsole.log("Doing overflow fix for "
  410. + Util.getConnectorString(componentConnector)
  411. + " in "
  412. + Util.getConnectorString(componentConnector
  413. .getParent()));
  414. }
  415. Element parentElement = componentConnector.getWidget()
  416. .getElement().getParentElement();
  417. Style style = parentElement.getStyle();
  418. String originalOverflow = style.getOverflow();
  419. if (originalOverflow != null
  420. && !originalOverflows.containsKey(parentElement)) {
  421. // Store original value for restore, but only the first time
  422. // the value is changed
  423. originalOverflows.put(parentElement, originalOverflow);
  424. }
  425. style.setOverflow(Overflow.HIDDEN);
  426. }
  427. pendingOverflowFixes.removeAll(delayedOverflowFixes);
  428. // Then ensure all scrolling elements are reflowed by measuring
  429. for (ComponentConnector componentConnector : pendingOverflowFixes) {
  430. componentConnector.getWidget().getElement().getParentElement()
  431. .getOffsetHeight();
  432. }
  433. // Finally restore old overflow value and update bookkeeping
  434. for (ComponentConnector componentConnector : pendingOverflowFixes) {
  435. Element parentElement = componentConnector.getWidget()
  436. .getElement().getParentElement();
  437. parentElement.getStyle().setProperty("overflow",
  438. originalOverflows.get(parentElement));
  439. layoutDependencyTree.setNeedsMeasure(componentConnector, true);
  440. }
  441. if (!pendingOverflowFixes.isEmpty()) {
  442. VConsole.log("Did overflow fix for "
  443. + pendingOverflowFixes.size() + " elements in "
  444. + duration.elapsedMillis() + " ms");
  445. }
  446. pendingOverflowFixes = delayedOverflowFixes;
  447. }
  448. int measureCount = 0;
  449. if (measureAll) {
  450. ComponentConnector[] connectors = ConnectorMap.get(connection)
  451. .getComponentConnectors();
  452. for (ComponentConnector connector : connectors) {
  453. measureConnector(connector);
  454. }
  455. for (ComponentConnector connector : connectors) {
  456. layoutDependencyTree.setNeedsMeasure(connector, false);
  457. }
  458. measureCount += connectors.length;
  459. }
  460. while (layoutDependencyTree.hasConnectorsToMeasure()) {
  461. Collection<ComponentConnector> measureTargets = layoutDependencyTree
  462. .getMeasureTargets();
  463. for (ComponentConnector connector : measureTargets) {
  464. measureConnector(connector);
  465. measureCount++;
  466. }
  467. for (ComponentConnector connector : measureTargets) {
  468. layoutDependencyTree.setNeedsMeasure(connector, false);
  469. }
  470. }
  471. return measureCount;
  472. }
  473. private void measureConnector(ComponentConnector connector) {
  474. Element element = connector.getWidget().getElement();
  475. MeasuredSize measuredSize = getMeasuredSize(connector);
  476. MeasureResult measureResult = measuredAndUpdate(element, measuredSize);
  477. if (measureResult.isChanged()) {
  478. onConnectorChange(connector, measureResult.isWidthChanged(),
  479. measureResult.isHeightChanged());
  480. }
  481. }
  482. private void onConnectorChange(ComponentConnector connector,
  483. boolean widthChanged, boolean heightChanged) {
  484. setNeedsOverflowFix(connector);
  485. if (heightChanged) {
  486. currentDependencyTree.markHeightAsChanged(connector);
  487. }
  488. if (widthChanged) {
  489. currentDependencyTree.markWidthAsChanged(connector);
  490. }
  491. }
  492. private void setNeedsOverflowFix(ComponentConnector connector) {
  493. // IE9 doesn't need the original fix, but for some reason it needs this
  494. if (BrowserInfo.get().requiresOverflowAutoFix()
  495. || BrowserInfo.get().isIE9()) {
  496. ComponentConnector scrollingBoundary = currentDependencyTree
  497. .getScrollingBoundary(connector);
  498. if (scrollingBoundary != null) {
  499. pendingOverflowFixes.add(scrollingBoundary);
  500. }
  501. }
  502. }
  503. private void measureNonConnectors() {
  504. for (Element element : measuredNonConnectorElements) {
  505. measuredAndUpdate(element, getMeasuredSize(element, null));
  506. }
  507. VConsole.log("Measured " + measuredNonConnectorElements.size()
  508. + " non connector elements");
  509. }
  510. private MeasureResult measuredAndUpdate(Element element,
  511. MeasuredSize measuredSize) {
  512. MeasureResult measureResult = measuredSize.measure(element);
  513. if (measureResult.isChanged()) {
  514. notifyListenersAndDepdendents(element,
  515. measureResult.isWidthChanged(),
  516. measureResult.isHeightChanged());
  517. }
  518. return measureResult;
  519. }
  520. private void notifyListenersAndDepdendents(Element element,
  521. boolean widthChanged, boolean heightChanged) {
  522. assert widthChanged || heightChanged;
  523. MeasuredSize measuredSize = getMeasuredSize(element, nullSize);
  524. JsArrayString dependents = measuredSize.getDependents();
  525. for (int i = 0; i < dependents.length(); i++) {
  526. String pid = dependents.get(i);
  527. ManagedLayout dependent = (ManagedLayout) connection
  528. .getConnectorMap().getConnector(pid);
  529. if (dependent != null) {
  530. if (heightChanged) {
  531. currentDependencyTree.setNeedsVerticalLayout(dependent,
  532. true);
  533. }
  534. if (widthChanged) {
  535. currentDependencyTree.setNeedsHorizontalLayout(dependent,
  536. true);
  537. }
  538. }
  539. }
  540. if (elementResizeListeners.containsKey(element)) {
  541. listenersToFire.add(element);
  542. }
  543. }
  544. private static boolean isManagedLayout(ComponentConnector connector) {
  545. return connector instanceof ManagedLayout;
  546. }
  547. public void forceLayout() {
  548. ConnectorMap connectorMap = connection.getConnectorMap();
  549. ComponentConnector[] componentConnectors = connectorMap
  550. .getComponentConnectors();
  551. for (ComponentConnector connector : componentConnectors) {
  552. if (connector instanceof ManagedLayout) {
  553. setNeedsLayout((ManagedLayout) connector);
  554. }
  555. }
  556. setEverythingNeedsMeasure();
  557. layoutNow();
  558. }
  559. /**
  560. * Marks that a ManagedLayout should be layouted in the next layout phase
  561. * even if none of the elements managed by the layout have been resized.
  562. *
  563. * @param layout
  564. * the managed layout that should be layouted
  565. */
  566. public final void setNeedsLayout(ManagedLayout layout) {
  567. setNeedsHorizontalLayout(layout);
  568. setNeedsVerticalLayout(layout);
  569. }
  570. /**
  571. * Marks that a ManagedLayout should be layouted horizontally in the next
  572. * layout phase even if none of the elements managed by the layout have been
  573. * resized horizontally.
  574. *
  575. * For SimpleManagedLayout which is always layouted in both directions, this
  576. * has the same effect as {@link #setNeedsLayout(ManagedLayout)}.
  577. *
  578. * @param layout
  579. * the managed layout that should be layouted
  580. */
  581. public final void setNeedsHorizontalLayout(ManagedLayout layout) {
  582. needsHorizontalLayout.add(layout);
  583. }
  584. /**
  585. * Marks that a ManagedLayout should be layouted vertically in the next
  586. * layout phase even if none of the elements managed by the layout have been
  587. * resized vertically.
  588. *
  589. * For SimpleManagedLayout which is always layouted in both directions, this
  590. * has the same effect as {@link #setNeedsLayout(ManagedLayout)}.
  591. *
  592. * @param layout
  593. * the managed layout that should be layouted
  594. */
  595. public final void setNeedsVerticalLayout(ManagedLayout layout) {
  596. needsVerticalLayout.add(layout);
  597. }
  598. /**
  599. * Gets the outer height (including margins, paddings and borders) of the
  600. * given element, provided that it has been measured. These elements are
  601. * guaranteed to be measured:
  602. * <ul>
  603. * <li>ManagedLayotus and their child Connectors
  604. * <li>Elements for which there is at least one ElementResizeListener
  605. * <li>Elements for which at least one ManagedLayout has registered a
  606. * dependency
  607. * </ul>
  608. *
  609. * -1 is returned if the element has not been measured. If 0 is returned, it
  610. * might indicate that the element is not attached to the DOM.
  611. *
  612. * @param element
  613. * the element to get the measured size for
  614. * @return the measured outer height (including margins, paddings and
  615. * borders) of the element in pixels.
  616. */
  617. public final int getOuterHeight(Element element) {
  618. return getMeasuredSize(element, nullSize).getOuterHeight();
  619. }
  620. /**
  621. * Gets the outer width (including margins, paddings and borders) of the
  622. * given element, provided that it has been measured. These elements are
  623. * guaranteed to be measured:
  624. * <ul>
  625. * <li>ManagedLayotus and their child Connectors
  626. * <li>Elements for which there is at least one ElementResizeListener
  627. * <li>Elements for which at least one ManagedLayout has registered a
  628. * dependency
  629. * </ul>
  630. *
  631. * -1 is returned if the element has not been measured. If 0 is returned, it
  632. * might indicate that the element is not attached to the DOM.
  633. *
  634. * @param element
  635. * the element to get the measured size for
  636. * @return the measured outer width (including margins, paddings and
  637. * borders) of the element in pixels.
  638. */
  639. public final int getOuterWidth(Element element) {
  640. return getMeasuredSize(element, nullSize).getOuterWidth();
  641. }
  642. /**
  643. * Gets the inner height (excluding margins, paddings and borders) of the
  644. * given element, provided that it has been measured. These elements are
  645. * guaranteed to be measured:
  646. * <ul>
  647. * <li>ManagedLayotus and their child Connectors
  648. * <li>Elements for which there is at least one ElementResizeListener
  649. * <li>Elements for which at least one ManagedLayout has registered a
  650. * dependency
  651. * </ul>
  652. *
  653. * -1 is returned if the element has not been measured. If 0 is returned, it
  654. * might indicate that the element is not attached to the DOM.
  655. *
  656. * @param element
  657. * the element to get the measured size for
  658. * @return the measured inner height (excluding margins, paddings and
  659. * borders) of the element in pixels.
  660. */
  661. public final int getInnerHeight(Element element) {
  662. return getMeasuredSize(element, nullSize).getInnerHeight();
  663. }
  664. /**
  665. * Gets the inner width (excluding margins, paddings and borders) of the
  666. * given element, provided that it has been measured. These elements are
  667. * guaranteed to be measured:
  668. * <ul>
  669. * <li>ManagedLayotus and their child Connectors
  670. * <li>Elements for which there is at least one ElementResizeListener
  671. * <li>Elements for which at least one ManagedLayout has registered a
  672. * dependency
  673. * </ul>
  674. *
  675. * -1 is returned if the element has not been measured. If 0 is returned, it
  676. * might indicate that the element is not attached to the DOM.
  677. *
  678. * @param element
  679. * the element to get the measured size for
  680. * @return the measured inner width (excluding margins, paddings and
  681. * borders) of the element in pixels.
  682. */
  683. public final int getInnerWidth(Element element) {
  684. return getMeasuredSize(element, nullSize).getInnerWidth();
  685. }
  686. /**
  687. * Gets the border height (top border + bottom border) of the given element,
  688. * provided that it has been measured. These elements are guaranteed to be
  689. * measured:
  690. * <ul>
  691. * <li>ManagedLayotus and their child Connectors
  692. * <li>Elements for which there is at least one ElementResizeListener
  693. * <li>Elements for which at least one ManagedLayout has registered a
  694. * dependency
  695. * </ul>
  696. *
  697. * A negative number is returned if the element has not been measured. If 0
  698. * is returned, it might indicate that the element is not attached to the
  699. * DOM.
  700. *
  701. * @param element
  702. * the element to get the measured size for
  703. * @return the measured border height (top border + bottom border) of the
  704. * element in pixels.
  705. */
  706. public final int getBorderHeight(Element element) {
  707. return getMeasuredSize(element, nullSize).getBorderHeight();
  708. }
  709. /**
  710. * Gets the padding height (top padding + bottom padding) of the given
  711. * element, provided that it has been measured. These elements are
  712. * guaranteed to be measured:
  713. * <ul>
  714. * <li>ManagedLayotus and their child Connectors
  715. * <li>Elements for which there is at least one ElementResizeListener
  716. * <li>Elements for which at least one ManagedLayout has registered a
  717. * dependency
  718. * </ul>
  719. *
  720. * A negative number is returned if the element has not been measured. If 0
  721. * is returned, it might indicate that the element is not attached to the
  722. * DOM.
  723. *
  724. * @param element
  725. * the element to get the measured size for
  726. * @return the measured padding height (top padding + bottom padding) of the
  727. * element in pixels.
  728. */
  729. public int getPaddingHeight(Element element) {
  730. return getMeasuredSize(element, nullSize).getPaddingHeight();
  731. }
  732. /**
  733. * Gets the border width (left border + right border) of the given element,
  734. * provided that it has been measured. These elements are guaranteed to be
  735. * measured:
  736. * <ul>
  737. * <li>ManagedLayotus and their child Connectors
  738. * <li>Elements for which there is at least one ElementResizeListener
  739. * <li>Elements for which at least one ManagedLayout has registered a
  740. * dependency
  741. * </ul>
  742. *
  743. * A negative number is returned if the element has not been measured. If 0
  744. * is returned, it might indicate that the element is not attached to the
  745. * DOM.
  746. *
  747. * @param element
  748. * the element to get the measured size for
  749. * @return the measured border width (left border + right border) of the
  750. * element in pixels.
  751. */
  752. public int getBorderWidth(Element element) {
  753. return getMeasuredSize(element, nullSize).getBorderWidth();
  754. }
  755. /**
  756. * Gets the padding width (left padding + right padding) of the given
  757. * element, provided that it has been measured. These elements are
  758. * guaranteed to be measured:
  759. * <ul>
  760. * <li>ManagedLayotus and their child Connectors
  761. * <li>Elements for which there is at least one ElementResizeListener
  762. * <li>Elements for which at least one ManagedLayout has registered a
  763. * dependency
  764. * </ul>
  765. *
  766. * A negative number is returned if the element has not been measured. If 0
  767. * is returned, it might indicate that the element is not attached to the
  768. * DOM.
  769. *
  770. * @param element
  771. * the element to get the measured size for
  772. * @return the measured padding width (left padding + right padding) of the
  773. * element in pixels.
  774. */
  775. public int getPaddingWidth(Element element) {
  776. return getMeasuredSize(element, nullSize).getPaddingWidth();
  777. }
  778. /**
  779. * Gets the top padding of the given element, provided that it has been
  780. * measured. These elements are guaranteed to be measured:
  781. * <ul>
  782. * <li>ManagedLayotus and their child Connectors
  783. * <li>Elements for which there is at least one ElementResizeListener
  784. * <li>Elements for which at least one ManagedLayout has registered a
  785. * dependency
  786. * </ul>
  787. *
  788. * A negative number is returned if the element has not been measured. If 0
  789. * is returned, it might indicate that the element is not attached to the
  790. * DOM.
  791. *
  792. * @param element
  793. * the element to get the measured size for
  794. * @return the measured top padding of the element in pixels.
  795. */
  796. public int getPaddingTop(Element element) {
  797. return getMeasuredSize(element, nullSize).getPaddingTop();
  798. }
  799. /**
  800. * Gets the left padding of the given element, provided that it has been
  801. * measured. These elements are guaranteed to be measured:
  802. * <ul>
  803. * <li>ManagedLayotus and their child Connectors
  804. * <li>Elements for which there is at least one ElementResizeListener
  805. * <li>Elements for which at least one ManagedLayout has registered a
  806. * dependency
  807. * </ul>
  808. *
  809. * A negative number is returned if the element has not been measured. If 0
  810. * is returned, it might indicate that the element is not attached to the
  811. * DOM.
  812. *
  813. * @param element
  814. * the element to get the measured size for
  815. * @return the measured left padding of the element in pixels.
  816. */
  817. public int getPaddingLeft(Element element) {
  818. return getMeasuredSize(element, nullSize).getPaddingLeft();
  819. }
  820. /**
  821. * Gets the bottom padding of the given element, provided that it has been
  822. * measured. These elements are guaranteed to be measured:
  823. * <ul>
  824. * <li>ManagedLayotus and their child Connectors
  825. * <li>Elements for which there is at least one ElementResizeListener
  826. * <li>Elements for which at least one ManagedLayout has registered a
  827. * dependency
  828. * </ul>
  829. *
  830. * A negative number is returned if the element has not been measured. If 0
  831. * is returned, it might indicate that the element is not attached to the
  832. * DOM.
  833. *
  834. * @param element
  835. * the element to get the measured size for
  836. * @return the measured bottom padding of the element in pixels.
  837. */
  838. public int getPaddingBottom(Element element) {
  839. return getMeasuredSize(element, nullSize).getPaddingBottom();
  840. }
  841. /**
  842. * Gets the right padding of the given element, provided that it has been
  843. * measured. These elements are guaranteed to be measured:
  844. * <ul>
  845. * <li>ManagedLayotus and their child Connectors
  846. * <li>Elements for which there is at least one ElementResizeListener
  847. * <li>Elements for which at least one ManagedLayout has registered a
  848. * dependency
  849. * </ul>
  850. *
  851. * A negative number is returned if the element has not been measured. If 0
  852. * is returned, it might indicate that the element is not attached to the
  853. * DOM.
  854. *
  855. * @param element
  856. * the element to get the measured size for
  857. * @return the measured right padding of the element in pixels.
  858. */
  859. public int getPaddingRight(Element element) {
  860. return getMeasuredSize(element, nullSize).getPaddingRight();
  861. }
  862. /**
  863. * Gets the top margin of the given element, provided that it has been
  864. * measured. These elements are guaranteed to be measured:
  865. * <ul>
  866. * <li>ManagedLayotus and their child Connectors
  867. * <li>Elements for which there is at least one ElementResizeListener
  868. * <li>Elements for which at least one ManagedLayout has registered a
  869. * dependency
  870. * </ul>
  871. *
  872. * A negative number is returned if the element has not been measured. If 0
  873. * is returned, it might indicate that the element is not attached to the
  874. * DOM.
  875. *
  876. * @param element
  877. * the element to get the measured size for
  878. * @return the measured top margin of the element in pixels.
  879. */
  880. public int getMarginTop(Element element) {
  881. return getMeasuredSize(element, nullSize).getMarginTop();
  882. }
  883. /**
  884. * Gets the right margin of the given element, provided that it has been
  885. * measured. These elements are guaranteed to be measured:
  886. * <ul>
  887. * <li>ManagedLayotus and their child Connectors
  888. * <li>Elements for which there is at least one ElementResizeListener
  889. * <li>Elements for which at least one ManagedLayout has registered a
  890. * dependency
  891. * </ul>
  892. *
  893. * A negative number is returned if the element has not been measured. If 0
  894. * is returned, it might indicate that the element is not attached to the
  895. * DOM.
  896. *
  897. * @param element
  898. * the element to get the measured size for
  899. * @return the measured right margin of the element in pixels.
  900. */
  901. public int getMarginRight(Element element) {
  902. return getMeasuredSize(element, nullSize).getMarginRight();
  903. }
  904. /**
  905. * Gets the bottom margin of the given element, provided that it has been
  906. * measured. These elements are guaranteed to be measured:
  907. * <ul>
  908. * <li>ManagedLayotus and their child Connectors
  909. * <li>Elements for which there is at least one ElementResizeListener
  910. * <li>Elements for which at least one ManagedLayout has registered a
  911. * dependency
  912. * </ul>
  913. *
  914. * A negative number is returned if the element has not been measured. If 0
  915. * is returned, it might indicate that the element is not attached to the
  916. * DOM.
  917. *
  918. * @param element
  919. * the element to get the measured size for
  920. * @return the measured bottom margin of the element in pixels.
  921. */
  922. public int getMarginBottom(Element element) {
  923. return getMeasuredSize(element, nullSize).getMarginBottom();
  924. }
  925. /**
  926. * Gets the left margin of the given element, provided that it has been
  927. * measured. These elements are guaranteed to be measured:
  928. * <ul>
  929. * <li>ManagedLayotus and their child Connectors
  930. * <li>Elements for which there is at least one ElementResizeListener
  931. * <li>Elements for which at least one ManagedLayout has registered a
  932. * dependency
  933. * </ul>
  934. *
  935. * A negative number is returned if the element has not been measured. If 0
  936. * is returned, it might indicate that the element is not attached to the
  937. * DOM.
  938. *
  939. * @param element
  940. * the element to get the measured size for
  941. * @return the measured left margin of the element in pixels.
  942. */
  943. public int getMarginLeft(Element element) {
  944. return getMeasuredSize(element, nullSize).getMarginLeft();
  945. }
  946. /**
  947. * Gets the combined top & bottom margin of the given element, provided that
  948. * they have been measured. These elements are guaranteed to be measured:
  949. * <ul>
  950. * <li>ManagedLayotus and their child Connectors
  951. * <li>Elements for which there is at least one ElementResizeListener
  952. * <li>Elements for which at least one ManagedLayout has registered a
  953. * dependency
  954. * </ul>
  955. *
  956. * A negative number is returned if the element has not been measured. If 0
  957. * is returned, it might indicate that the element is not attached to the
  958. * DOM.
  959. *
  960. * @param element
  961. * the element to get the measured margin for
  962. * @return the measured top+bottom margin of the element in pixels.
  963. */
  964. public int getMarginHeight(Element element) {
  965. return getMarginTop(element) + getMarginBottom(element);
  966. }
  967. /**
  968. * Gets the combined left & right margin of the given element, provided that
  969. * they have been measured. These elements are guaranteed to be measured:
  970. * <ul>
  971. * <li>ManagedLayotus and their child Connectors
  972. * <li>Elements for which there is at least one ElementResizeListener
  973. * <li>Elements for which at least one ManagedLayout has registered a
  974. * dependency
  975. * </ul>
  976. *
  977. * A negative number is returned if the element has not been measured. If 0
  978. * is returned, it might indicate that the element is not attached to the
  979. * DOM.
  980. *
  981. * @param element
  982. * the element to get the measured margin for
  983. * @return the measured left+right margin of the element in pixels.
  984. */
  985. public int getMarginWidth(Element element) {
  986. return getMarginLeft(element) + getMarginRight(element);
  987. }
  988. /**
  989. * Registers the outer height (including margins, borders and paddings) of a
  990. * component. This can be used as an optimization by ManagedLayouts; by
  991. * informing the LayoutManager about what size a component will have, the
  992. * layout propagation can continue directly without first measuring the
  993. * potentially resized elements.
  994. *
  995. * @param component
  996. * the component for which the size is reported
  997. * @param outerHeight
  998. * the new outer height (including margins, borders and paddings)
  999. * of the component in pixels
  1000. */
  1001. public void reportOuterHeight(ComponentConnector component, int outerHeight) {
  1002. MeasuredSize measuredSize = getMeasuredSize(component);
  1003. if (isLayoutRunning()) {
  1004. boolean heightChanged = measuredSize.setOuterHeight(outerHeight);
  1005. if (heightChanged) {
  1006. onConnectorChange(component, false, true);
  1007. notifyListenersAndDepdendents(component.getWidget()
  1008. .getElement(), false, true);
  1009. }
  1010. currentDependencyTree.setNeedsVerticalMeasure(component, false);
  1011. } else if (measuredSize.getOuterHeight() != outerHeight) {
  1012. setNeedsMeasure(component);
  1013. }
  1014. }
  1015. /**
  1016. * Registers the height reserved for a relatively sized component. This can
  1017. * be used as an optimization by ManagedLayouts; by informing the
  1018. * LayoutManager about what size a component will have, the layout
  1019. * propagation can continue directly without first measuring the potentially
  1020. * resized elements.
  1021. *
  1022. * @param component
  1023. * the relatively sized component for which the size is reported
  1024. * @param assignedHeight
  1025. * the inner height of the relatively sized component's parent
  1026. * element in pixels
  1027. */
  1028. public void reportHeightAssignedToRelative(ComponentConnector component,
  1029. int assignedHeight) {
  1030. assert component.isRelativeHeight();
  1031. float percentSize = parsePercent(component.getState().height == null ? ""
  1032. : component.getState().height);
  1033. int effectiveHeight = Math.round(assignedHeight * (percentSize / 100));
  1034. reportOuterHeight(component, effectiveHeight);
  1035. }
  1036. /**
  1037. * Registers the width reserved for a relatively sized component. This can
  1038. * be used as an optimization by ManagedLayouts; by informing the
  1039. * LayoutManager about what size a component will have, the layout
  1040. * propagation can continue directly without first measuring the potentially
  1041. * resized elements.
  1042. *
  1043. * @param component
  1044. * the relatively sized component for which the size is reported
  1045. * @param assignedWidth
  1046. * the inner width of the relatively sized component's parent
  1047. * element in pixels
  1048. */
  1049. public void reportWidthAssignedToRelative(ComponentConnector component,
  1050. int assignedWidth) {
  1051. assert component.isRelativeWidth();
  1052. float percentSize = parsePercent(component.getState().width == null ? ""
  1053. : component.getState().width);
  1054. int effectiveWidth = Math.round(assignedWidth * (percentSize / 100));
  1055. reportOuterWidth(component, effectiveWidth);
  1056. }
  1057. private static float parsePercent(String size) {
  1058. return Float.parseFloat(size.substring(0, size.length() - 1));
  1059. }
  1060. /**
  1061. * Registers the outer width (including margins, borders and paddings) of a
  1062. * component. This can be used as an optimization by ManagedLayouts; by
  1063. * informing the LayoutManager about what size a component will have, the
  1064. * layout propagation can continue directly without first measuring the
  1065. * potentially resized elements.
  1066. *
  1067. * @param component
  1068. * the component for which the size is reported
  1069. * @param outerWidth
  1070. * the new outer width (including margins, borders and paddings)
  1071. * of the component in pixels
  1072. */
  1073. public void reportOuterWidth(ComponentConnector component, int outerWidth) {
  1074. MeasuredSize measuredSize = getMeasuredSize(component);
  1075. if (isLayoutRunning()) {
  1076. boolean widthChanged = measuredSize.setOuterWidth(outerWidth);
  1077. if (widthChanged) {
  1078. onConnectorChange(component, true, false);
  1079. notifyListenersAndDepdendents(component.getWidget()
  1080. .getElement(), true, false);
  1081. }
  1082. currentDependencyTree.setNeedsHorizontalMeasure(component, false);
  1083. } else if (measuredSize.getOuterWidth() != outerWidth) {
  1084. setNeedsMeasure(component);
  1085. }
  1086. }
  1087. /**
  1088. * Adds a listener that will be notified whenever the size of a specific
  1089. * element changes. Adding a listener to an element also ensures that all
  1090. * sizes for that element will be available starting from the next layout
  1091. * phase.
  1092. *
  1093. * @param element
  1094. * the element that should be checked for size changes
  1095. * @param listener
  1096. * an ElementResizeListener that will be informed whenever the
  1097. * size of the target element has changed
  1098. */
  1099. public void addElementResizeListener(Element element,
  1100. ElementResizeListener listener) {
  1101. Collection<ElementResizeListener> listeners = elementResizeListeners
  1102. .get(element);
  1103. if (listeners == null) {
  1104. listeners = new HashSet<ElementResizeListener>();
  1105. elementResizeListeners.put(element, listeners);
  1106. ensureMeasured(element);
  1107. }
  1108. listeners.add(listener);
  1109. }
  1110. /**
  1111. * Removes an element resize listener from the provided element. This might
  1112. * cause this LayoutManager to stop tracking the size of the element if no
  1113. * other sources are interested in the size.
  1114. *
  1115. * @param element
  1116. * the element to which the element resize listener was
  1117. * previously added
  1118. * @param listener
  1119. * the ElementResizeListener that should no longer get informed
  1120. * about size changes to the target element.
  1121. */
  1122. public void removeElementResizeListener(Element element,
  1123. ElementResizeListener listener) {
  1124. Collection<ElementResizeListener> listeners = elementResizeListeners
  1125. .get(element);
  1126. if (listeners != null) {
  1127. listeners.remove(listener);
  1128. if (listeners.isEmpty()) {
  1129. elementResizeListeners.remove(element);
  1130. stopMeasuringIfUnecessary(element);
  1131. }
  1132. }
  1133. }
  1134. private void stopMeasuringIfUnecessary(Element element) {
  1135. if (!needsMeasure(element)) {
  1136. measuredNonConnectorElements.remove(element);
  1137. setMeasuredSize(element, null);
  1138. }
  1139. }
  1140. /**
  1141. * Informs this LayoutManager that the size of a component might have
  1142. * changed. If there is no upcoming layout phase, a new layout phase is
  1143. * scheduled. This method should be used whenever a size might have changed
  1144. * from outside of Vaadin's normal update phase, e.g. when an icon has been
  1145. * loaded or when the user resizes some part of the UI using the mouse.
  1146. *
  1147. * @param component
  1148. * the component whose size might have changed.
  1149. */
  1150. public void setNeedsMeasure(ComponentConnector component) {
  1151. if (isLayoutRunning()) {
  1152. currentDependencyTree.setNeedsMeasure(component, true);
  1153. } else {
  1154. needsMeasure.add(component);
  1155. layoutLater();
  1156. }
  1157. }
  1158. public void setEverythingNeedsMeasure() {
  1159. everythingNeedsMeasure = true;
  1160. }
  1161. /**
  1162. * Clean measured sizes which are no longer needed. Only for IE8.
  1163. */
  1164. protected void cleanMeasuredSizes() {
  1165. }
  1166. }