Path: blob/master/src/java.desktop/share/classes/sun/font/GraphicComponent.java
41154 views
/*1* Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425/*26* (C) Copyright IBM Corp. 1998-2003, All Rights Reserved27*28*/2930package sun.font;3132import java.awt.Font;33import java.awt.Graphics2D;34import java.awt.Rectangle;35import java.awt.Shape;36import java.awt.font.FontRenderContext;37import java.awt.font.LineMetrics;38import java.awt.font.GraphicAttribute;39import java.awt.font.GlyphJustificationInfo;40import java.awt.geom.AffineTransform;41import java.awt.geom.GeneralPath;42import java.awt.geom.Rectangle2D;43import java.text.Bidi;44import java.util.Map;4546public final class GraphicComponent implements TextLineComponent,47Decoration.Label {4849public static final float GRAPHIC_LEADING = 2;5051private GraphicAttribute graphic;52private int graphicCount;53private int[] charsLtoV; // possibly null54private byte[] levels; // possibly null5556// evaluated in computeVisualBounds57private Rectangle2D visualBounds = null;5859// used everywhere so we'll cache it60private float graphicAdvance;6162private AffineTransform baseTx;6364private CoreMetrics cm;65private Decoration decorator;666768/**69* Create a new GraphicComponent. start and limit are indices70* into charLtoV and levels. charsLtoV and levels may be adopted.71*/72public GraphicComponent(GraphicAttribute graphic,73Decoration decorator,74int[] charsLtoV,75byte[] levels,76int start,77int limit,78AffineTransform baseTx) {7980if (limit <= start) {81throw new IllegalArgumentException("0 or negative length in GraphicComponent");82}83this.graphic = graphic;84this.graphicAdvance = graphic.getAdvance();85this.decorator = decorator;86this.cm = createCoreMetrics(graphic);87this.baseTx = baseTx;8889initLocalOrdering(charsLtoV, levels, start, limit);90}9192private GraphicComponent(GraphicComponent parent, int start, int limit, int dir) {9394this.graphic = parent.graphic;95this.graphicAdvance = parent.graphicAdvance;96this.decorator = parent.decorator;97this.cm = parent.cm;98this.baseTx = parent.baseTx;99100int[] charsLtoV = null;101byte[] levels = null;102103if (dir == UNCHANGED) {104charsLtoV = parent.charsLtoV;105levels = parent.levels;106}107else if (dir == LEFT_TO_RIGHT || dir == RIGHT_TO_LEFT) {108limit -= start;109start = 0;110if (dir == RIGHT_TO_LEFT) {111charsLtoV = new int[limit];112levels = new byte[limit];113for (int i=0; i < limit; i++) {114charsLtoV[i] = limit-i-1;115levels[i] = (byte) 1;116}117}118}119else {120throw new IllegalArgumentException("Invalid direction flag");121}122123initLocalOrdering(charsLtoV, levels, start, limit);124}125126/**127* Initialize graphicCount, also charsLtoV and levels arrays.128*/129private void initLocalOrdering(int[] charsLtoV,130byte[] levels,131int start,132int limit) {133134this.graphicCount = limit - start; // todo: should be codepoints?135136if (charsLtoV == null || charsLtoV.length == graphicCount) {137this.charsLtoV = charsLtoV;138}139else {140this.charsLtoV = BidiUtils.createNormalizedMap(charsLtoV, levels, start, limit);141}142143if (levels == null || levels.length == graphicCount) {144this.levels = levels;145}146else {147this.levels = new byte[graphicCount];148System.arraycopy(levels, start, this.levels, 0, graphicCount);149}150}151152public boolean isSimple() {153return false;154}155156public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) {157throw new InternalError("do not call if isSimple returns false");158}159160public Rectangle2D handleGetVisualBounds() {161162Rectangle2D bounds = graphic.getBounds();163164float width = (float) bounds.getWidth() +165graphicAdvance * (graphicCount-1);166167return new Rectangle2D.Float((float) bounds.getX(),168(float) bounds.getY(),169width,170(float) bounds.getHeight());171}172173public CoreMetrics getCoreMetrics() {174return cm;175}176177public static CoreMetrics createCoreMetrics(GraphicAttribute graphic) {178return new CoreMetrics(graphic.getAscent(),179graphic.getDescent(),180GRAPHIC_LEADING,181graphic.getAscent() + graphic.getDescent() + GRAPHIC_LEADING,182graphic.getAlignment(),183new float[] { 0, -graphic.getAscent() / 2, -graphic.getAscent() },184-graphic.getAscent() / 2,185graphic.getAscent() / 12,186graphic.getDescent() / 3,187graphic.getAscent() / 12,1880, // ss offset1890); // italic angle -- need api for this190}191192public float getItalicAngle() {193194return 0;195}196197public Rectangle2D getVisualBounds() {198199if (visualBounds == null) {200visualBounds = decorator.getVisualBounds(this);201}202Rectangle2D.Float bounds = new Rectangle2D.Float();203bounds.setRect(visualBounds);204return bounds;205}206207public Shape handleGetOutline(float x, float y) {208double[] matrix = { 1, 0, 0, 1, x, y };209210if (graphicCount == 1) {211AffineTransform tx = new AffineTransform(matrix);212return graphic.getOutline(tx);213}214215GeneralPath gp = new GeneralPath();216for (int i = 0; i < graphicCount; ++i) {217AffineTransform tx = new AffineTransform(matrix);218gp.append(graphic.getOutline(tx), false);219matrix[4] += graphicAdvance;220}221222return gp;223}224225public AffineTransform getBaselineTransform() {226return baseTx;227}228229public Shape getOutline(float x, float y) {230231return decorator.getOutline(this, x, y);232}233234public void handleDraw(Graphics2D g2d, float x, float y) {235236for (int i=0; i < graphicCount; i++) {237238graphic.draw(g2d, x, y);239x += graphicAdvance;240}241}242243public void draw(Graphics2D g2d, float x, float y) {244245decorator.drawTextAndDecorations(this, g2d, x, y);246}247248public Rectangle2D getCharVisualBounds(int index) {249250return decorator.getCharVisualBounds(this, index);251}252253public int getNumCharacters() {254255return graphicCount;256}257258public float getCharX(int index) {259260int visIndex = charsLtoV==null? index : charsLtoV[index];261return graphicAdvance * visIndex;262}263264public float getCharY(int index) {265266return 0;267}268269public float getCharAdvance(int index) {270271return graphicAdvance;272}273274public boolean caretAtOffsetIsValid(int index) {275276return true;277}278279public Rectangle2D handleGetCharVisualBounds(int index) {280281Rectangle2D bounds = graphic.getBounds();282// don't modify their rectangle, just in case they don't copy283284Rectangle2D.Float charBounds = new Rectangle2D.Float();285charBounds.setRect(bounds);286charBounds.x += graphicAdvance * index;287288return charBounds;289}290291// measures characters in context, in logical order292public int getLineBreakIndex(int start, float width) {293294int index = (int) (width / graphicAdvance);295if (index > graphicCount - start) {296index = graphicCount - start;297}298return index;299}300301// measures characters in context, in logical order302public float getAdvanceBetween(int start, int limit) {303304return graphicAdvance * (limit - start);305}306307public Rectangle2D getLogicalBounds() {308309float left = 0;310float top = -cm.ascent;311float width = graphicAdvance * graphicCount;312float height = cm.descent - top;313314return new Rectangle2D.Float(left, top, width, height);315}316317public float getAdvance() {318return graphicAdvance * graphicCount;319}320321public Rectangle2D getItalicBounds() {322return getLogicalBounds();323}324325public TextLineComponent getSubset(int start, int limit, int dir) {326327if (start < 0 || limit > graphicCount || start >= limit) {328throw new IllegalArgumentException("Invalid range. start="329+start+"; limit="+limit);330}331332if (start == 0 && limit == graphicCount && dir == UNCHANGED) {333return this;334}335336return new GraphicComponent(this, start, limit, dir);337}338339public String toString() {340341return "[graphic=" + graphic + ":count=" + getNumCharacters() + "]";342}343344/**345* Return the number of justification records this uses.346*/347public int getNumJustificationInfos() {348return 0;349}350351/**352* Return GlyphJustificationInfo objects for the characters between353* charStart and charLimit, starting at offset infoStart. Infos354* will be in visual order. All positions between infoStart and355* getNumJustificationInfos will be set. If a position corresponds356* to a character outside the provided range, it is set to null.357*/358public void getJustificationInfos(GlyphJustificationInfo[] infos, int infoStart, int charStart, int charLimit) {359}360361/**362* Apply deltas to the data in this component, starting at offset363* deltaStart, and return the new component. There are two floats364* for each justification info, for a total of 2 * getNumJustificationInfos.365* The first delta is the left adjustment, the second is the right366* adjustment.367* <p>368* If flags[0] is true on entry, rejustification is allowed. If369* the new component requires rejustification (ligatures were370* formed or split), flags[0] will be set on exit.371*/372public TextLineComponent applyJustificationDeltas(float[] deltas, int deltaStart, boolean[] flags) {373return this;374}375}376377378