org.apache.batik.gvt.flow.LineInfo Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of batik-gvt Show documentation
Show all versions of batik-gvt Show documentation
Batik Graphics Vector Tree (GVT)
The newest version!
/* 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. */ package org.apache.batik.gvt.flow; import java.awt.geom.Point2D; import org.apache.batik.gvt.font.GVTGlyphVector; /** * One line Class Desc * * Complete Class Desc * * @author deweese * @version $Id$ */ public class LineInfo { FlowRegions fr; double lineHeight = -1; double ascent = -1; double descent = -1; double hLeading = -1; double baseline; int numGlyphs; int words = 0; int size=0; GlyphGroupInfo [] ggis=null; int newSize=0; GlyphGroupInfo [] newGGIS=null; int numRanges; double [] ranges; double [] rangeAdv; BlockInfo bi = null; boolean paraStart; boolean paraEnd; protected static final int FULL_WORD = 0; protected static final int FULL_ADV = 1; public LineInfo(FlowRegions fr, BlockInfo bi, boolean paraStart) { this.fr = fr; this.bi = bi; this.lineHeight = bi.getLineHeight(); this.ascent = bi.getAscent(); this.descent = bi.getDescent(); this.hLeading = (lineHeight-(ascent+descent))/2; this.baseline = (float)(fr.getCurrentY()+hLeading+ascent); this.paraStart = paraStart; this.paraEnd = false; if (lineHeight > 0) { fr.newLineHeight(lineHeight); updateRangeInfo(); } } public void setParaEnd(boolean paraEnd) { this.paraEnd = paraEnd; } public boolean addWord(WordInfo wi) { double nlh = wi.getLineHeight(); if (nlh <= lineHeight) return insertWord(wi); fr.newLineHeight(nlh); if (!updateRangeInfo()) { if (lineHeight > 0) // restore old LH fr.newLineHeight(lineHeight); return false; } if (!insertWord(wi)) { if (lineHeight > 0) // Failure, restore old line Height. setLineHeight(lineHeight); return false; } // Success, word fits on line. lineHeight = nlh; if (wi.getAscent() > ascent) ascent = wi.getAscent(); if (wi.getDescent() > descent) descent = wi.getDescent(); hLeading = (nlh-(ascent+descent))/2; baseline = (float)(fr.getCurrentY()+hLeading+ascent); return true; } public boolean insertWord(WordInfo wi) { // Merge wi's glyph groups into the current GGI's. // This puts them into newGGIS, so if it fails we can // retain to the old ggis array. mergeGlyphGroups(wi); if (!assignGlyphGroupRanges(newSize, newGGIS)) return false; // Swap in to GG info. swapGlyphGroupInfo(); return true; } static final float MAX_COMPRESS=0.1f; static final float COMRESS_SCALE=3; public boolean assignGlyphGroupRanges(int ggSz, GlyphGroupInfo []ggis) { int i=0, r=0; while (r
* into the glyph groups that are already on this line. * It does no fit checking, just adds them in the * proper place in therange) { // "i" can't fit in this region see if "i-1" can. i--; ladv = 0; if (i < 0) break; ggi = ggis[i]; if (r != ggi.getRange()) // Not from this range nothing fits. break; rangeAdvance -= ggi.getAdvance(); ladv = ggi.getLastAdvance(); } i++; rangeAdv[r] = rangeAdvance + ladv; r++; if (i == ggSz) return true; } return false; } /** * This method updates the line height and recalculates * the available flow ranges for the line. */ public boolean setLineHeight(double lh) { fr.newLineHeight(lh); if (updateRangeInfo()) { lineHeight = lh; return true; } // restore line height. if (lineHeight > 0) fr.newLineHeight(lineHeight); return false; } public double getCurrentY() { return fr.getCurrentY(); } public boolean gotoY(double y) { if (fr.gotoY(y)) return true; if (lineHeight > 0) updateRangeInfo(); this.baseline = (float)(fr.getCurrentY()+hLeading+ascent); return false; } protected boolean updateRangeInfo() { fr.resetRange(); int nr = fr.getNumRangeOnLine(); if (nr == 0) return false; numRanges = nr; if (ranges == null) { rangeAdv = new double[numRanges]; ranges = new double[2*numRanges]; } else if (numRanges > rangeAdv.length) { int sz = 2*rangeAdv.length; if (sz < numRanges) sz = numRanges; rangeAdv = new double[sz]; ranges = new double[2*sz]; } for (int r=0; r wi newGGIS
data member. */ protected void mergeGlyphGroups(WordInfo wi) { int numGG = wi.getNumGlyphGroups(); newSize = 0; if (ggis == null) { // first glyph group on line just add them. newSize = numGG; newGGIS = new GlyphGroupInfo[numGG]; for (int i=0; i< numGG; i++) newGGIS[i] = wi.getGlyphGroup(i); } else { // We need to merge the new glyph groups with the // existing glyph Groups. int s = 0; int i = 0; GlyphGroupInfo nggi = wi.getGlyphGroup(i); int nStart = nggi.getStart(); GlyphGroupInfo oggi = ggis[size-1]; int oStart = oggi.getStart(); newGGIS = assureSize(newGGIS, size+numGG); if (nStart < oStart) { oggi = ggis[s]; oStart = oggi.getStart(); while((s" + // newGGIS[i].end); // } } public void layout() { if (size == 0) return; // This is needed because we know that in most cases // the addition of the last word failed. In the case of // BIDI this will mess up region assignments. // If one wanted to you could check on BIDI, and/or // lastPara. assignGlyphGroupRanges(size, ggis); GVTGlyphVector gv = ggis[0].getGlyphVector(); int justType = FULL_WORD; double ggAdv = 0; double gAdv = 0; // Calculate the number of Glyph Groups and the number // of glpyhs in each range for use with full justification. int []rangeGG = new int[numRanges]; int []rangeG = new int[numRanges]; GlyphGroupInfo []rangeLastGGI = new GlyphGroupInfo[numRanges]; GlyphGroupInfo ggi = ggis[0]; int r = ggi.getRange(); rangeGG[r]++; rangeG [r] += ggi.getGlyphCount(); for (int i=1; i = 1) ggAdv = delta/numSp; } else { int numSp = rangeG[currRange]-1; if (numSp >= 1) gAdv = delta/numSp; } } break; case BlockInfo.ALIGN_START: break; case BlockInfo.ALIGN_MIDDLE: locX += (range-rAdv)/2; break; case BlockInfo.ALIGN_END: locX += (range-rAdv); break; } } else if ((pggi!= null) && pggi.getHideLast()) { // Hide last glyph from prev glyph group (soft hyphen etc). gv.setGlyphVisible(pggi.getEnd(), false); } int start = ggi.getStart(); int end = ggi.getEnd(); boolean [] hide = ggi.getHide(); Point2D p2d = gv.getGlyphPosition(start); double deltaX = p2d.getX(); double advAdj = 0; for (int g=start; g<=end; g++) { Point2D np2d = gv.getGlyphPosition(g+1); if (hide[g-start]) { gv.setGlyphVisible(g, false); advAdj += np2d.getX()-p2d.getX(); } else { gv.setGlyphVisible(g, true); } p2d.setLocation(p2d.getX()-deltaX-advAdj+locX, p2d.getY()+baseline); gv.setGlyphPosition(g, p2d); p2d = np2d; advAdj -= gAdv; } if (ggi.getHideLast()) locX += ggi.getAdvance()-advAdj; else locX += ggi.getAdvance()-advAdj+ggAdv; } } public static GlyphGroupInfo [] assureSize (GlyphGroupInfo [] ggis, int sz) { if (ggis == null) { if (sz < 10) sz = 10; return new GlyphGroupInfo[sz]; } if (sz <= ggis.length) return ggis; int nsz = ggis.length*2; if (nsz < sz) nsz = sz; return new GlyphGroupInfo[nsz]; } }