summaryrefslogtreecommitdiffstats
path: root/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java
diff options
context:
space:
mode:
Diffstat (limited to 'awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java')
-rw-r--r--awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java209
1 files changed, 209 insertions, 0 deletions
diff --git a/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java b/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java
new file mode 100644
index 0000000..be5762a
--- /dev/null
+++ b/awt/org/apache/harmony/awt/gl/font/TextMetricsCalculator.java
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+/**
+ * @author Oleg V. Khaschansky
+ * @version $Revision$
+ *
+ */
+
+package org.apache.harmony.awt.gl.font;
+
+import java.awt.font.LineMetrics;
+import java.awt.font.GraphicAttribute;
+import java.awt.Font;
+import java.util.HashMap;
+import java.util.ArrayList;
+
+import org.apache.harmony.awt.internal.nls.Messages;
+
+/**
+ * This class operates with an arbitrary text string which can include
+ * any number of style, font and direction runs. It is responsible for computation
+ * of the text metrics, such as ascent, descent, leading and advance. Actually,
+ * each text run segment contains logic which allows it to compute its own metrics and
+ * responsibility of this class is to combine metrics for all segments included in the text,
+ * managed by the associated TextRunBreaker object.
+ */
+public class TextMetricsCalculator {
+ TextRunBreaker breaker; // Associated run breaker
+
+ // Metrics
+ float ascent = 0;
+ float descent = 0;
+ float leading = 0;
+ float advance = 0;
+
+ private float baselineOffsets[];
+ int baselineIndex;
+
+ public TextMetricsCalculator(TextRunBreaker breaker) {
+ this.breaker = breaker;
+ checkBaselines();
+ }
+
+ /**
+ * Returns either values cached by checkBaselines method or reasonable
+ * values for the TOP and BOTTOM alignments.
+ * @param baselineIndex - baseline index
+ * @return baseline offset
+ */
+ float getBaselineOffset(int baselineIndex) {
+ if (baselineIndex >= 0) {
+ return baselineOffsets[baselineIndex];
+ } else if (baselineIndex == GraphicAttribute.BOTTOM_ALIGNMENT) {
+ return descent;
+ } else if (baselineIndex == GraphicAttribute.TOP_ALIGNMENT) {
+ return -ascent;
+ } else {
+ // awt.3F=Invalid baseline index
+ throw new IllegalArgumentException(Messages.getString("awt.3F")); //$NON-NLS-1$
+ }
+ }
+
+ public float[] getBaselineOffsets() {
+ float ret[] = new float[baselineOffsets.length];
+ System.arraycopy(baselineOffsets, 0, ret, 0, baselineOffsets.length);
+ return ret;
+ }
+
+ /**
+ * Take baseline offsets from the first font or graphic attribute
+ * and normalizes them, than caches the results.
+ */
+ public void checkBaselines() {
+ // Take baseline offsets of the first font and normalize them
+ HashMap<Integer, Font> fonts = breaker.fonts;
+
+ Object val = fonts.get(new Integer(0));
+
+ if (val instanceof Font) {
+ Font firstFont = (Font) val;
+ LineMetrics lm = firstFont.getLineMetrics(breaker.text, 0, 1, breaker.frc);
+ baselineOffsets = lm.getBaselineOffsets();
+ baselineIndex = lm.getBaselineIndex();
+ } else if (val instanceof GraphicAttribute) {
+ // Get first graphic attribute and use it
+ GraphicAttribute ga = (GraphicAttribute) val;
+
+ int align = ga.getAlignment();
+
+ if (
+ align == GraphicAttribute.TOP_ALIGNMENT ||
+ align == GraphicAttribute.BOTTOM_ALIGNMENT
+ ) {
+ baselineIndex = GraphicAttribute.ROMAN_BASELINE;
+ } else {
+ baselineIndex = align;
+ }
+
+ baselineOffsets = new float[3];
+ baselineOffsets[0] = 0;
+ baselineOffsets[1] = (ga.getDescent() - ga.getAscent()) / 2.f;
+ baselineOffsets[2] = -ga.getAscent();
+ } else { // Use defaults - Roman baseline and zero offsets
+ baselineIndex = GraphicAttribute.ROMAN_BASELINE;
+ baselineOffsets = new float[3];
+ }
+
+ // Normalize offsets if needed
+ if (baselineOffsets[baselineIndex] != 0) {
+ float baseOffset = baselineOffsets[baselineIndex];
+ for (int i = 0; i < baselineOffsets.length; i++) {
+ baselineOffsets[i] -= baseOffset;
+ }
+ }
+ }
+
+ /**
+ * Computes metrics for the text managed by the associated TextRunBreaker
+ */
+ void computeMetrics() {
+
+ ArrayList<TextRunSegment> segments = breaker.runSegments;
+
+ float maxHeight = 0;
+ float maxHeightLeading = 0;
+
+ for (int i = 0; i < segments.size(); i++) {
+ TextRunSegment segment = segments.get(i);
+ BasicMetrics metrics = segment.metrics;
+ int baseline = metrics.baseLineIndex;
+
+ if (baseline >= 0) {
+ float baselineOffset = baselineOffsets[metrics.baseLineIndex];
+ float fixedDescent = metrics.descent + baselineOffset;
+
+ ascent = Math.max(ascent, metrics.ascent - baselineOffset);
+ descent = Math.max(descent, fixedDescent);
+ leading = Math.max(leading, fixedDescent + metrics.leading);
+ } else { // Position is not fixed by the baseline, need sum of ascent and descent
+ float height = metrics.ascent + metrics.descent;
+
+ maxHeight = Math.max(maxHeight, height);
+ maxHeightLeading = Math.max(maxHeightLeading, height + metrics.leading);
+ }
+ }
+
+ // Need to increase sizes for graphics?
+ if (maxHeightLeading != 0) {
+ descent = Math.max(descent, maxHeight - ascent);
+ leading = Math.max(leading, maxHeightLeading - ascent);
+ }
+
+ // Normalize leading
+ leading -= descent;
+
+ BasicMetrics currMetrics;
+ float currAdvance = 0;
+
+ for (int i = 0; i < segments.size(); i++) {
+ TextRunSegment segment = segments.get(breaker.getSegmentFromVisualOrder(i));
+ currMetrics = segment.metrics;
+
+ segment.y = getBaselineOffset(currMetrics.baseLineIndex)
+ + currMetrics.superScriptOffset;
+ segment.x = currAdvance;
+
+ currAdvance += segment.getAdvance();
+ }
+
+ advance = currAdvance;
+ }
+
+ /**
+ * Computes metrics and creates BasicMetrics object from them
+ * @return basic metrics
+ */
+ public BasicMetrics createMetrics() {
+ computeMetrics();
+ return new BasicMetrics(this);
+ }
+
+ /**
+ * Corrects advance after justification. Gets BasicMetrics object
+ * and updates advance stored into it.
+ * @param metrics - metrics with outdated advance which should be corrected
+ */
+ public void correctAdvance(BasicMetrics metrics) {
+ ArrayList<TextRunSegment> segments = breaker.runSegments;
+ TextRunSegment segment = segments.get(breaker
+ .getSegmentFromVisualOrder(segments.size() - 1));
+
+ advance = segment.x + segment.getAdvance();
+ metrics.advance = advance;
+ }
+}