/** * This function merges the glyph groups from <tt>wi<tt/> into the glyph groups that are already * on this line. It does no fit checking, just adds them in the proper place in the * <tt>newGGIS</tt> 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 < size) && (i < numGG)) { if (nStart < oStart) { newGGIS[newSize++] = nggi; i++; if (i < numGG) { nggi = wi.getGlyphGroup(i); nStart = nggi.getStart(); } } else { newGGIS[newSize++] = oggi; s++; if (s < size) { oggi = ggis[s]; oStart = oggi.getStart(); } } } } while (s < size) { newGGIS[newSize++] = ggis[s++]; } while (i < numGG) { newGGIS[newSize++] = wi.getGlyphGroup(i++); } } // for (int i=0; i<newSize; i++) { // System.err.println("GGIS["+i+"]: " + newGGIS[i].start + " -> " + // newGGIS[i].end); // } }
public boolean assignGlyphGroupRanges(int ggSz, GlyphGroupInfo[] ggis) { int i = 0, r = 0; while (r < numRanges) { double range = ranges[2 * r + 1] - ranges[2 * r]; float adv = 0; float rangeAdvance = 0; while (i < ggSz) { GlyphGroupInfo ggi = ggis[i]; ggi.setRange(r); adv = ggi.getAdvance(); double delta = range - (rangeAdvance + adv); if (delta < 0) break; i++; rangeAdvance += adv; } // Check last glyphGroup anyways... if (i == ggSz) { i--; rangeAdvance -= adv; } GlyphGroupInfo ggi = ggis[i]; float ladv = ggi.getLastAdvance(); while (rangeAdvance + ladv > range) { // "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; }
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 < size; i++) { ggi = ggis[i]; r = ggi.getRange(); if ((rangeLastGGI[r] == null) || !rangeLastGGI[r].getHideLast()) rangeGG[r]++; rangeLastGGI[r] = ggi; rangeG[r] += ggi.getGlyphCount(); GlyphGroupInfo pggi = ggis[i - 1]; int pr = pggi.getRange(); if (r != pr) rangeG[pr] += pggi.getLastGlyphCount() - pggi.getGlyphCount(); } rangeG[r] += ggi.getLastGlyphCount() - ggi.getGlyphCount(); int currRange = -1; double locX = 0, range = 0, rAdv = 0; r = -1; ggi = null; for (int i = 0; i < size; i++) { GlyphGroupInfo pggi = ggi; int prevRange = currRange; ggi = ggis[i]; currRange = ggi.getRange(); if (currRange != prevRange) { locX = ranges[2 * currRange]; range = ranges[2 * currRange + 1] - locX; rAdv = rangeAdv[currRange]; int textAlign = bi.getTextAlignment(); if ((paraEnd) && (textAlign == BlockInfo.ALIGN_FULL)) textAlign = BlockInfo.ALIGN_START; switch (textAlign) { default: case BlockInfo.ALIGN_FULL: { double delta = range - rAdv; if (justType == FULL_WORD) { int numSp = rangeGG[currRange] - 1; if (numSp >= 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; } }