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.5KB

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