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; } }