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.

ComputedStyle.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  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 com.google.gwt.core.client.JavaScriptObject;
  18. import com.google.gwt.dom.client.Element;
  19. public class ComputedStyle {
  20. private static final String CONTENT_BOX = "content-box";
  21. protected final JavaScriptObject computedStyle;
  22. private final Element elem;
  23. /**
  24. * Gets this element's computed style object which can be used to gather
  25. * information about the current state of the rendered node.
  26. * <p>
  27. * Note that this method is expensive. Wherever possible, reuse the returned
  28. * object.
  29. *
  30. * @param elem
  31. * the element
  32. */
  33. public ComputedStyle(Element elem) {
  34. computedStyle = getComputedStyle(elem);
  35. this.elem = elem;
  36. }
  37. private static native JavaScriptObject getComputedStyle(Element elem)
  38. /*-{
  39. if (elem.nodeType != 1) {
  40. return {};
  41. }
  42. if ($wnd.document.defaultView && $wnd.document.defaultView.getComputedStyle) {
  43. return $wnd.document.defaultView.getComputedStyle(elem, null);
  44. }
  45. if (elem.currentStyle) {
  46. return elem.currentStyle;
  47. }
  48. }-*/;
  49. /**
  50. * Gets the value of the given property.
  51. *
  52. * @param name
  53. * name of the CSS property in camelCase
  54. * @return the value of the property, normalized for across browsers (each
  55. * browser returns pixel values whenever possible).
  56. */
  57. public final native String getProperty(String name)
  58. /*-{
  59. var cs = this.@com.vaadin.client.ComputedStyle::computedStyle;
  60. var elem = this.@com.vaadin.client.ComputedStyle::elem;
  61. // Border values need to be checked separately. The width might have a
  62. // meaningful value even if the border style is "none". In that case the
  63. // value should be 0.
  64. if (name.indexOf("border") > -1 && name.indexOf("Width") > -1) {
  65. var borderStyleProp = name.substring(0,name.length-5) + "Style";
  66. if (cs.getPropertyValue)
  67. var borderStyle = cs.getPropertyValue(borderStyleProp);
  68. else // IE
  69. var borderStyle = cs[borderStyleProp];
  70. if (borderStyle == "none")
  71. return "0px";
  72. }
  73. if (cs.getPropertyValue) {
  74. // Convert name to dashed format
  75. name = name.replace(/([A-Z])/g, "-$1").toLowerCase('en');
  76. var ret = cs.getPropertyValue(name);
  77. } else {
  78. var ret = cs[name];
  79. var style = elem.style;
  80. // From the awesome hack by Dean Edwards
  81. // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
  82. // If we're not dealing with a regular pixel number
  83. // but a number that has a weird ending, we need to convert it to pixels
  84. if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
  85. // Remember the original values
  86. var left = style.left, rsLeft = elem.runtimeStyle.left;
  87. // Put in the new values to get a computed value out
  88. elem.runtimeStyle.left = cs.left;
  89. style.left = ret || 0;
  90. ret = style.pixelLeft + "px";
  91. // Revert the changed values
  92. style.left = left;
  93. elem.runtimeStyle.left = rsLeft;
  94. }
  95. }
  96. // Normalize margin values. This is not totally valid, but in most cases
  97. // it is what the user wants to know.
  98. if (name.indexOf("margin") > -1 && ret == "auto") {
  99. return "0px";
  100. }
  101. // Some browsers return undefined width and height values as "auto", so
  102. // we need to retrieve those ourselves.
  103. if (name == "width" && ret == "auto") {
  104. ret = elem.clientWidth + "px";
  105. } else if (name == "height" && ret == "auto") {
  106. ret = elem.clientHeight + "px";
  107. }
  108. return ret;
  109. }-*/;
  110. /**
  111. * Retrieves the given computed property as an integer.
  112. *
  113. * Returns 0 if the property cannot be converted to an integer
  114. *
  115. * @param name
  116. * the property to retrieve
  117. * @return the integer value of the property or 0
  118. */
  119. public final int getIntProperty(String name) {
  120. Profiler.enter("ComputedStyle.getIntProperty");
  121. String value = getProperty(name);
  122. int result = parseIntNative(value);
  123. Profiler.leave("ComputedStyle.getIntProperty");
  124. return result;
  125. }
  126. /**
  127. * Retrieves the given computed property as a double.
  128. *
  129. * Returns NaN if the property cannot be converted to a double
  130. *
  131. * @since 7.5.1
  132. * @param name
  133. * the property to retrieve
  134. * @return the double value of the property
  135. */
  136. public final double getDoubleProperty(String name) {
  137. Profiler.enter("ComputedStyle.getDoubleProperty");
  138. String value = getProperty(name);
  139. double result = parseDoubleNative(value);
  140. Profiler.leave("ComputedStyle.getDoubleProperty");
  141. return result;
  142. }
  143. /**
  144. * Get current margin values from the DOM.
  145. *
  146. * @return an array containing four values for the four edges, in the
  147. * default CSS order: top, right, bottom, left.
  148. */
  149. public final int[] getMargin() {
  150. int[] margin = { 0, 0, 0, 0 };
  151. margin[0] = getIntProperty("marginTop");
  152. margin[1] = getIntProperty("marginRight");
  153. margin[2] = getIntProperty("marginBottom");
  154. margin[3] = getIntProperty("marginLeft");
  155. return margin;
  156. }
  157. /**
  158. * Get current padding values from the DOM.
  159. *
  160. * @return an array containing four values for the four edges, in the
  161. * default CSS order: top, right, bottom, left.
  162. */
  163. public final int[] getPadding() {
  164. int[] padding = { 0, 0, 0, 0 };
  165. padding[0] = getIntProperty("paddingTop");
  166. padding[1] = getIntProperty("paddingRight");
  167. padding[2] = getIntProperty("paddingBottom");
  168. padding[3] = getIntProperty("paddingLeft");
  169. return padding;
  170. }
  171. /**
  172. * Get current border values from the DOM.
  173. *
  174. * @return an array containing four values for the four edges, in the
  175. * default CSS order: top, right, bottom, left.
  176. */
  177. public final int[] getBorder() {
  178. int[] border = { 0, 0, 0, 0 };
  179. border[0] = getIntProperty("borderTopWidth");
  180. border[1] = getIntProperty("borderRightWidth");
  181. border[2] = getIntProperty("borderBottomWidth");
  182. border[3] = getIntProperty("borderLeftWidth");
  183. return border;
  184. }
  185. /**
  186. * Returns the current width from the DOM.
  187. *
  188. * @since 7.5.1
  189. * @return the computed width
  190. */
  191. public double getWidth() {
  192. return getDoubleProperty("width");
  193. }
  194. /**
  195. * Returns the current height from the DOM.
  196. *
  197. * @since 7.5.1
  198. * @return the computed height
  199. */
  200. public double getHeight() {
  201. return getDoubleProperty("height");
  202. }
  203. /**
  204. * Takes a String value e.g. "12px" and parses that to Integer 12.
  205. *
  206. * @param value
  207. * a value starting with a number
  208. * @return Integer the value from the string before any non-numeric
  209. * characters. If the value cannot be parsed to a number, returns
  210. * <code>null</code>.
  211. *
  212. * @deprecated Since 7.1.4, the method {@link #parseIntNative(String)} is
  213. * used internally and this method does not belong in the public
  214. * API of {@link ComputedStyle}. {@link #parseInt(String)} might
  215. * be removed or moved to a utility class in future versions.
  216. */
  217. @Deprecated
  218. public static native Integer parseInt(final String value)
  219. /*-{
  220. var number = parseInt(value, 10);
  221. if (isNaN(number))
  222. return null;
  223. else
  224. // $entry not needed as function is not exported
  225. return @java.lang.Integer::valueOf(I)(number);
  226. }-*/;
  227. /**
  228. * Takes a String value e.g. "12px" and parses that to int 12.
  229. *
  230. * <p>
  231. * This method returns 0 for <code>NaN</code>.
  232. *
  233. * @param String
  234. * a value starting with a number
  235. * @return the value from the string before any non-numeric characters.
  236. * If the value cannot be parsed to a number, returns 0.
  237. */
  238. private static native int parseIntNative(final String value)
  239. /*-{
  240. var number = parseInt(value, 10);
  241. if (isNaN(number))
  242. return 0;
  243. else
  244. return number;
  245. }-*/;
  246. /**
  247. * Takes a String value e.g. "12.3px" and parses that to a double, 12.3.
  248. *
  249. * @param String
  250. * a value starting with a number
  251. * @return the value from the string before any non-numeric characters or
  252. * NaN if the value cannot be parsed as a number
  253. */
  254. private static native double parseDoubleNative(final String value)
  255. /*-{
  256. return parseFloat(value);
  257. }-*/;
  258. /**
  259. * Returns the sum of the top and bottom border width.
  260. *
  261. * @since 7.5.3
  262. * @return the sum of the top and bottom border
  263. */
  264. public double getBorderHeight() {
  265. double borderHeight = getDoubleProperty("borderTopWidth");
  266. borderHeight += getDoubleProperty("borderBottomWidth");
  267. return borderHeight;
  268. }
  269. /**
  270. * Returns the sum of the left and right border width.
  271. *
  272. * @since 7.5.3
  273. * @return the sum of the left and right border
  274. */
  275. public double getBorderWidth() {
  276. double borderWidth = getDoubleProperty("borderLeftWidth");
  277. borderWidth += getDoubleProperty("borderRightWidth");
  278. return borderWidth;
  279. }
  280. /**
  281. * Returns the sum of the top and bottom padding.
  282. *
  283. * @since 7.5.3
  284. * @return the sum of the top and bottom padding
  285. */
  286. public double getPaddingHeight() {
  287. double paddingHeight = getDoubleProperty("paddingTop");
  288. paddingHeight += getDoubleProperty("paddingBottom");
  289. return paddingHeight;
  290. }
  291. /**
  292. * Returns the sum of the top and bottom padding.
  293. *
  294. * @since 7.5.3
  295. * @return the sum of the left and right padding
  296. */
  297. public double getPaddingWidth() {
  298. double paddingWidth = getDoubleProperty("paddingLeft");
  299. paddingWidth += getDoubleProperty("paddingRight");
  300. return paddingWidth;
  301. }
  302. /**
  303. * Returns the sum of the top and bottom margin.
  304. *
  305. * @since 7.5.6
  306. * @return the sum of the top and bottom margin
  307. */
  308. public double getMarginHeight() {
  309. double marginHeight = getDoubleProperty("marginTop");
  310. marginHeight += getDoubleProperty("marginBottom");
  311. return marginHeight;
  312. }
  313. /**
  314. * Returns the sum of the left and right margin.
  315. *
  316. * @since 7.5.6
  317. * @return the sum of the left and right margin
  318. */
  319. public double getMarginWidth() {
  320. double marginWidth = getDoubleProperty("marginLeft");
  321. marginWidth += getDoubleProperty("marginRight");
  322. return marginWidth;
  323. }
  324. /**
  325. * Returns the current height, padding and border from the DOM.
  326. *
  327. * @return the computed height including padding and borders
  328. */
  329. public double getHeightIncludingBorderPadding() {
  330. double h = getHeight();
  331. if (BrowserInfo.get().isIE() || isContentBox()) {
  332. // IE11 always returns only the height without padding/border
  333. h += getBorderHeight() + getPaddingHeight();
  334. }
  335. return h;
  336. }
  337. /**
  338. * Returns the current width, padding and border from the DOM.
  339. *
  340. * @return the computed width including padding and borders
  341. */
  342. public double getWidthIncludingBorderPadding() {
  343. double w = getWidth();
  344. if (BrowserInfo.get().isIE() || isContentBox()) {
  345. // IE11 always returns only the width without padding/border
  346. w += getBorderWidth() + getPaddingWidth();
  347. }
  348. return w;
  349. }
  350. private boolean isContentBox() {
  351. return getBoxSizing().equals(CONTENT_BOX);
  352. }
  353. /**
  354. * Returns the value of the boxSizing property.
  355. *
  356. * @return the value of the boxSizing property
  357. */
  358. private String getBoxSizing() {
  359. return getProperty("boxSizing");
  360. }
  361. }