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.

MeasuredSize.java 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. * Copyright 2000-2014 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 com.google.gwt.core.client.JsArrayString;
  18. import com.google.gwt.dom.client.Element;
  19. public class MeasuredSize {
  20. private final static boolean debugSizeChanges = false;
  21. public static class MeasureResult {
  22. private final boolean widthChanged;
  23. private final boolean heightChanged;
  24. private MeasureResult(boolean widthChanged, boolean heightChanged) {
  25. this.widthChanged = widthChanged;
  26. this.heightChanged = heightChanged;
  27. }
  28. public boolean isHeightChanged() {
  29. return heightChanged;
  30. }
  31. public boolean isWidthChanged() {
  32. return widthChanged;
  33. }
  34. public boolean isChanged() {
  35. return heightChanged || widthChanged;
  36. }
  37. }
  38. private int width = -1;
  39. private int height = -1;
  40. private int[] paddings = new int[4];
  41. private int[] borders = new int[4];
  42. private int[] margins = new int[4];
  43. private FastStringSet dependents = FastStringSet.create();
  44. public int getOuterHeight() {
  45. return height;
  46. }
  47. public int getOuterWidth() {
  48. return width;
  49. }
  50. public void addDependent(String pid) {
  51. dependents.add(pid);
  52. }
  53. public void removeDependent(String pid) {
  54. dependents.remove(pid);
  55. }
  56. public boolean hasDependents() {
  57. return !dependents.isEmpty();
  58. }
  59. public JsArrayString getDependents() {
  60. return dependents.dump();
  61. }
  62. private static int sumWidths(int[] sizes) {
  63. return sizes[1] + sizes[3];
  64. }
  65. private static int sumHeights(int[] sizes) {
  66. return sizes[0] + sizes[2];
  67. }
  68. public int getInnerHeight() {
  69. return height - sumHeights(margins) - sumHeights(borders)
  70. - sumHeights(paddings);
  71. }
  72. public int getInnerWidth() {
  73. return width - sumWidths(margins) - sumWidths(borders)
  74. - sumWidths(paddings);
  75. }
  76. public boolean setOuterHeight(int height) {
  77. if (this.height != height) {
  78. this.height = height;
  79. return true;
  80. } else {
  81. return false;
  82. }
  83. }
  84. public boolean setOuterWidth(int width) {
  85. if (this.width != width) {
  86. this.width = width;
  87. return true;
  88. } else {
  89. return false;
  90. }
  91. }
  92. public int getBorderHeight() {
  93. return sumHeights(borders);
  94. }
  95. public int getBorderWidth() {
  96. return sumWidths(borders);
  97. }
  98. public int getPaddingHeight() {
  99. return sumHeights(paddings);
  100. }
  101. public int getPaddingWidth() {
  102. return sumWidths(paddings);
  103. }
  104. public int getMarginHeight() {
  105. return sumHeights(margins);
  106. }
  107. public int getMarginWidth() {
  108. return sumWidths(margins);
  109. }
  110. public int getMarginTop() {
  111. return margins[0];
  112. }
  113. public int getMarginRight() {
  114. return margins[1];
  115. }
  116. public int getMarginBottom() {
  117. return margins[2];
  118. }
  119. public int getMarginLeft() {
  120. return margins[3];
  121. }
  122. public int getBorderTop() {
  123. return borders[0];
  124. }
  125. public int getBorderRight() {
  126. return borders[1];
  127. }
  128. public int getBorderBottom() {
  129. return borders[2];
  130. }
  131. public int getBorderLeft() {
  132. return borders[3];
  133. }
  134. public int getPaddingTop() {
  135. return paddings[0];
  136. }
  137. public int getPaddingRight() {
  138. return paddings[1];
  139. }
  140. public int getPaddingBottom() {
  141. return paddings[2];
  142. }
  143. public int getPaddingLeft() {
  144. return paddings[3];
  145. }
  146. public MeasureResult measure(Element element) {
  147. Profiler.enter("MeasuredSize.measure");
  148. boolean heightChanged = false;
  149. boolean widthChanged = false;
  150. Profiler.enter("new ComputedStyle");
  151. ComputedStyle computedStyle = new ComputedStyle(element);
  152. int[] paddings = computedStyle.getPadding();
  153. // Some browsers do not reflow until accessing data from the computed
  154. // style object
  155. Profiler.leave("new ComputedStyle");
  156. Profiler.enter("Measure paddings");
  157. if (!heightChanged && hasHeightChanged(this.paddings, paddings)) {
  158. debugSizeChange(element, "Height (padding)", this.paddings,
  159. paddings);
  160. heightChanged = true;
  161. }
  162. if (!widthChanged && hasWidthChanged(this.paddings, paddings)) {
  163. debugSizeChange(element, "Width (padding)", this.paddings, paddings);
  164. widthChanged = true;
  165. }
  166. this.paddings = paddings;
  167. Profiler.leave("Measure paddings");
  168. Profiler.enter("Measure margins");
  169. int[] margins = computedStyle.getMargin();
  170. if (!heightChanged && hasHeightChanged(this.margins, margins)) {
  171. debugSizeChange(element, "Height (margins)", this.margins, margins);
  172. heightChanged = true;
  173. }
  174. if (!widthChanged && hasWidthChanged(this.margins, margins)) {
  175. debugSizeChange(element, "Width (margins)", this.margins, margins);
  176. widthChanged = true;
  177. }
  178. this.margins = margins;
  179. Profiler.leave("Measure margins");
  180. Profiler.enter("Measure borders");
  181. int[] borders = computedStyle.getBorder();
  182. if (!heightChanged && hasHeightChanged(this.borders, borders)) {
  183. debugSizeChange(element, "Height (borders)", this.borders, borders);
  184. heightChanged = true;
  185. }
  186. if (!widthChanged && hasWidthChanged(this.borders, borders)) {
  187. debugSizeChange(element, "Width (borders)", this.borders, borders);
  188. widthChanged = true;
  189. }
  190. this.borders = borders;
  191. Profiler.leave("Measure borders");
  192. Profiler.enter("Measure height");
  193. int requiredHeight = Util.getRequiredHeight(element);
  194. int marginHeight = sumHeights(margins);
  195. int oldHeight = height;
  196. int oldWidth = width;
  197. if (setOuterHeight(requiredHeight + marginHeight)) {
  198. debugSizeChange(element, "Height (outer)", oldHeight, height);
  199. heightChanged = true;
  200. }
  201. Profiler.leave("Measure height");
  202. Profiler.enter("Measure width");
  203. int requiredWidth = Util.getRequiredWidth(element);
  204. int marginWidth = sumWidths(margins);
  205. if (setOuterWidth(requiredWidth + marginWidth)) {
  206. debugSizeChange(element, "Width (outer)", oldWidth, width);
  207. widthChanged = true;
  208. }
  209. Profiler.leave("Measure width");
  210. Profiler.leave("MeasuredSize.measure");
  211. return new MeasureResult(widthChanged, heightChanged);
  212. }
  213. private void debugSizeChange(Element element, String sizeChangeType,
  214. int[] changedFrom, int[] changedTo) {
  215. debugSizeChange(element, sizeChangeType,
  216. java.util.Arrays.asList(changedFrom).toString(),
  217. java.util.Arrays.asList(changedTo).toString());
  218. }
  219. private void debugSizeChange(Element element, String sizeChangeType,
  220. int changedFrom, int changedTo) {
  221. debugSizeChange(element, sizeChangeType, String.valueOf(changedFrom),
  222. String.valueOf(changedTo));
  223. }
  224. private void debugSizeChange(Element element, String sizeChangeType,
  225. String changedFrom, String changedTo) {
  226. if (debugSizeChanges) {
  227. VConsole.log(sizeChangeType + " has changed from " + changedFrom
  228. + " to " + changedTo + " for " + element.toString());
  229. }
  230. }
  231. private static boolean hasWidthChanged(int[] sizes1, int[] sizes2) {
  232. return sizes1[1] != sizes2[1] || sizes1[3] != sizes2[3];
  233. }
  234. private static boolean hasHeightChanged(int[] sizes1, int[] sizes2) {
  235. return sizes1[0] != sizes2[0] || sizes1[2] != sizes2[2];
  236. }
  237. }