// Copyright 2012 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.collide.client.document.linedimensions; import com.google.collide.client.util.Elements; import com.google.collide.client.util.dom.FontDimensionsCalculator; import com.google.collide.client.util.dom.FontDimensionsCalculator.FontDimensions; import com.google.collide.shared.util.StringUtils; import elemental.css.CSSStyleDeclaration; import elemental.html.Element; /** * A {@link MeasurementProvider} which utilizes the DOM to measure a string. */ class BrowserMeasurementProvider implements MeasurementProvider { /** * The minimum number of characters we require to measure. * #getRenderedStringWidth(String) will use this to duplicate the string when * measuring short strings. */ /* * this is not completely arbitrary, too low of a number and WebKit * mis-calculates the width due to rounding errors and minor variations in * zoom level character widths. As a reference, 10.0 was too small. */ private static final double MINIMUM_TEXT_LENGTH = 30.0; private final FontDimensions fontDimensions; private final Element element; public BrowserMeasurementProvider(FontDimensionsCalculator calculator) { fontDimensions = calculator.getFontDimensions(); element = Elements.createSpanElement(calculator.getFontClassName()); element.getStyle().setVisibility(CSSStyleDeclaration.Visibility.HIDDEN); element.getStyle().setPosition(CSSStyleDeclaration.Position.ABSOLUTE); Elements.getBody().appendChild(element); } @Override public double getCharacterWidth() { return fontDimensions.getCharacterWidth(); } @Override public double measureStringWidth(String text) { LineDimensionsUtils.markTimeline(getClass(), "Starting measurement of text"); int instances = (int) Math.ceil(MINIMUM_TEXT_LENGTH / text.length()); /* * We add a hardspace since this prevents bi-directional combining marks * from screwing with our measurement (these spaces must be removed from our * result at the end). */ element.setTextContent(StringUtils.repeatString(text + "\u00A0", instances)); double width = (element.getBoundingClientRect().getWidth() - (getCharacterWidth() * instances)) / instances; LineDimensionsUtils.markTimeline(getClass(), "End measurement of text"); return width; } }