1 18 19 package org.apache.batik.gvt.flow; 20 21 import java.awt.geom.Point2D ; 22 import org.apache.batik.gvt.font.GVTGlyphVector; 23 24 32 public class LineInfo { 33 FlowRegions fr; 34 double lineHeight = -1; 35 double ascent = -1; 36 double descent = -1; 37 double hLeading = -1; 38 double baseline; 39 int numGlyphs; 40 int words = 0; 41 42 int size=0; 43 GlyphGroupInfo [] ggis=null; 44 int newSize=0; 45 GlyphGroupInfo [] newGGIS=null; 46 47 int numRanges; 48 double [] ranges; 49 double [] rangeAdv; 50 51 BlockInfo bi = null; 52 boolean paraStart; 53 boolean paraEnd; 54 55 protected final static int FULL_WORD = 0; 56 protected final static int FULL_ADV = 1; 57 58 59 public LineInfo(FlowRegions fr, BlockInfo bi, boolean paraStart) { 60 this.fr = fr; 61 this.bi = bi; 62 this.lineHeight = bi.getLineHeight(); 63 this.ascent = bi.getAscent(); 64 this.descent = bi.getDescent(); 65 this.hLeading = (lineHeight-(ascent+descent))/2; 66 this.baseline = (float)(fr.getCurrentY()+hLeading+ascent); 67 this.paraStart = paraStart; 68 this.paraEnd = false; 69 if (lineHeight > 0) { 70 fr.newLineHeight(lineHeight); 71 updateRangeInfo(); 72 } 73 74 } 75 76 public void setParaEnd(boolean paraEnd) { 77 this.paraEnd = paraEnd; 78 } 79 80 public boolean addWord(WordInfo wi) { 81 double nlh = wi.getLineHeight(); 82 if (nlh <= lineHeight) 83 return insertWord(wi); 84 fr.newLineHeight(nlh); 85 86 if (!updateRangeInfo()) { 87 if (lineHeight > 0) fr.newLineHeight(lineHeight); 89 return false; 90 } 91 92 if (!insertWord(wi)) { 93 if (lineHeight > 0) setLineHeight(lineHeight); 95 return false; 96 } 97 98 lineHeight = nlh; 100 if (wi.getAscent() > ascent) 101 ascent = wi.getAscent(); 102 if (wi.getDescent() > descent) 103 descent = wi.getDescent(); 104 hLeading = (nlh-(ascent+descent))/2; 105 baseline = (float)(fr.getCurrentY()+hLeading+ascent); 106 return true; 107 } 108 109 public boolean insertWord(WordInfo wi) { 110 mergeGlyphGroups(wi); 114 115 if (!assignGlyphGroupRanges(newSize, newGGIS)) 116 return false; 117 118 swapGlyphGroupInfo(); 120 121 return true; 122 } 123 static final float MAX_COMPRESS=0.1f; 124 static final float COMRESS_SCALE=3; 125 126 public boolean assignGlyphGroupRanges(int ggSz, GlyphGroupInfo []ggis) { 127 int i=0, r=0; 128 while (r<numRanges) { 129 double range = ranges[2*r+1]-ranges[2*r]; 130 float adv=0; 131 float rangeAdvance = 0; 132 double pdelta = range; 133 134 while (i<ggSz) { 135 GlyphGroupInfo ggi = ggis[i]; 136 ggi.setRange(r); 137 adv = ggi.getAdvance(); 138 double delta = range-(rangeAdvance + adv); 139 if (delta < 0) break; 140 141 i++; 142 rangeAdvance += adv; 143 } 144 145 if (i == ggSz) { 147 i--; 148 rangeAdvance -= adv; 149 } 150 151 GlyphGroupInfo ggi = ggis[i]; 152 float ladv = ggi.getLastAdvance(); 153 while (rangeAdvance + ladv > range) { 154 i--; 156 ladv = 0; 157 if (i < 0) break; 158 ggi = ggis[i]; 159 if (r != ggi.getRange()) break; 161 162 rangeAdvance -= ggi.getAdvance(); 163 ladv = ggi.getLastAdvance(); 164 } 165 166 i++; 167 rangeAdv[r] = rangeAdvance + ladv; 168 r++; 169 if (i == ggSz) return true; 170 } 171 return false; 172 } 173 174 178 public boolean setLineHeight(double lh) { 179 fr.newLineHeight(lh); 180 181 if (updateRangeInfo()) { 182 lineHeight = lh; 183 return true; 184 } 185 186 if (lineHeight > 0) 188 fr.newLineHeight(lineHeight); 189 return false; 190 } 191 192 public double getCurrentY() { 193 return fr.getCurrentY(); 194 } 195 196 public boolean gotoY(double y) { 197 if (fr.gotoY(y)) 198 return true; 199 if (lineHeight > 0) 200 updateRangeInfo(); 201 this.baseline = (float)(fr.getCurrentY()+hLeading+ascent); 202 return false; 203 } 204 205 protected boolean updateRangeInfo() { 206 fr.resetRange(); 207 int nr = fr.getNumRangeOnLine(); 208 if (nr == 0) 209 return false; 210 211 numRanges = nr; 212 213 if (ranges == null) { 214 rangeAdv = new double[numRanges]; 215 ranges = new double[2*numRanges]; 216 } else if (numRanges > rangeAdv.length) { 217 int sz = 2*rangeAdv.length; 218 if (sz < numRanges) sz = numRanges; 219 rangeAdv = new double[sz]; 220 ranges = new double[2*sz]; 221 } 222 223 for (int r=0; r<numRanges; r++) { 224 double [] rangeBounds = fr.nextRange(); 225 double r0 = rangeBounds[0]; 228 if (r == 0) { 229 double delta = bi.getLeftMargin(); 230 if (paraStart) { 231 double indent = bi.getIndent(); 232 if (delta < -indent) delta = 0; 234 else delta += indent; 235 } 236 r0 += delta; 237 } 238 239 double r1 = rangeBounds[1]; 240 if (r == numRanges-1) 241 r1 -= bi.getRightMargin(); 242 ranges[2*r] = r0; 243 ranges[2*r+1] = r1; 244 } 245 246 return true; 247 } 248 249 protected void swapGlyphGroupInfo() { 250 GlyphGroupInfo [] tmp = ggis; 251 ggis = newGGIS; 252 newGGIS = tmp; 253 254 size = newSize; 255 newSize = 0; 256 } 257 258 264 protected void mergeGlyphGroups(WordInfo wi) { 265 int numGG = wi.getNumGlyphGroups(); 266 newSize = 0; 267 if (ggis == null) { 268 newSize = numGG; 270 newGGIS = new GlyphGroupInfo[numGG]; 271 for (int i=0; i< numGG; i++) 272 newGGIS[i] = wi.getGlyphGroup(i); 273 } else { 274 int s = 0; 277 int i = 0; 278 GlyphGroupInfo nggi = wi.getGlyphGroup(i); 279 int nStart = nggi.getStart(); 280 281 GlyphGroupInfo oggi = ggis[size-1]; 282 int oStart = oggi.getStart(); 283 284 newGGIS = assureSize(newGGIS, size+numGG); 285 if (nStart < oStart) { 286 oggi = ggis[s]; 287 oStart = oggi.getStart(); 288 while((s<size)&&(i<numGG)) { 289 if (nStart < oStart) { 290 newGGIS[newSize++] = nggi; 291 i++; 292 if (i<numGG) { 293 nggi = wi.getGlyphGroup(i); 294 nStart = nggi.getStart(); 295 } 296 } else { 297 newGGIS[newSize++] = oggi; 298 s++; 299 if (s<size) { 300 oggi = ggis[s]; 301 oStart = oggi.getStart(); 302 } 303 } 304 } 305 } 306 while(s<size) { 307 newGGIS[newSize++] = ggis[s++]; 308 } 309 while(i<numGG) { 310 newGGIS[newSize++] = wi.getGlyphGroup(i++); 311 } 312 } 313 } 318 319 320 public void layout() { 321 if (size == 0) return; 322 323 assignGlyphGroupRanges(size, ggis); 329 330 GVTGlyphVector gv = ggis[0].getGlyphVector(); 331 int justType = FULL_WORD; 332 double ggAdv = 0; 333 double gAdv = 0; 334 335 int []rangeGG = new int[numRanges]; 338 int []rangeG = new int[numRanges]; 339 GlyphGroupInfo []rangeLastGGI = new GlyphGroupInfo[numRanges]; 340 GlyphGroupInfo ggi = ggis[0]; 341 int r = ggi.getRange(); 342 rangeGG[r]++; 343 rangeG [r] += ggi.getGlyphCount(); 344 for (int i=1; i<size; i++) { 345 ggi = ggis[i]; 346 r = ggi.getRange(); 347 if ((rangeLastGGI[r]==null) || !rangeLastGGI[r].getHideLast()) 348 rangeGG[r]++; 349 rangeLastGGI[r] = ggi; 350 351 rangeG [r] += ggi.getGlyphCount(); 352 353 GlyphGroupInfo pggi = ggis[i-1]; 354 int pr = pggi.getRange(); 355 if (r != pr) 356 rangeG[pr]+= pggi.getLastGlyphCount()-pggi.getGlyphCount(); 357 } 358 rangeG[r]+= ggi.getLastGlyphCount()-ggi.getGlyphCount(); 359 360 int currRange = -1; 361 double locX=0, range=0, rAdv=0; 362 r=-1; 363 ggi = null; 364 for (int i=0; i<size; i++) { 365 GlyphGroupInfo pggi = ggi; 366 int prevRange = currRange; 367 368 ggi = ggis[i]; 369 currRange = ggi.getRange(); 370 371 if (currRange != prevRange) { 372 locX = ranges[2*currRange]; 373 range = ranges[2*currRange+1]-locX; 374 rAdv = rangeAdv[currRange]; 375 int textAlign = bi.getTextAlignment(); 376 if ((paraEnd) && (textAlign == BlockInfo.ALIGN_FULL)) 377 textAlign = BlockInfo.ALIGN_START; 378 379 switch (textAlign) { 380 default: 381 case BlockInfo.ALIGN_FULL: { 382 double delta = range-rAdv; 383 if (justType == FULL_WORD) { 384 int numSp = rangeGG[currRange]-1; 385 if (numSp >= 1) 386 ggAdv = delta/numSp; 387 } else { 388 int numSp = rangeG[currRange]-1; 389 if (numSp >= 1) gAdv = delta/numSp; 390 } 391 } break; 392 case BlockInfo.ALIGN_START: break; 393 case BlockInfo.ALIGN_MIDDLE: locX += (range-rAdv)/2; break; 394 case BlockInfo.ALIGN_END: locX += (range-rAdv); break; 395 } 396 } else if ((pggi!= null) && pggi.getHideLast()) { 397 gv.setGlyphVisible(pggi.getEnd(), false); 399 } 400 401 int start = ggi.getStart(); 402 int end = ggi.getEnd(); 403 boolean [] hide = ggi.getHide(); 404 Point2D p2d = gv.getGlyphPosition(start); 405 double deltaX = p2d.getX(); 406 double advAdj = 0; 407 for (int g=start; g<=end; g++) { 408 Point2D np2d = gv.getGlyphPosition(g+1); 409 if (hide[g-start]) { 410 gv.setGlyphVisible(g, false); 411 advAdj += np2d.getX()-p2d.getX(); 412 } else { 413 gv.setGlyphVisible(g, true); 414 } 415 p2d.setLocation(p2d.getX()-deltaX-advAdj+locX, 416 p2d.getY()+baseline); 417 gv.setGlyphPosition(g, p2d); 418 p2d = np2d; 419 advAdj -= gAdv; 420 } 421 if (ggi.getHideLast()) 422 locX += ggi.getAdvance()-advAdj; 423 else 424 locX += ggi.getAdvance()-advAdj+ggAdv; 425 } 426 } 427 428 public static GlyphGroupInfo [] assureSize 429 (GlyphGroupInfo [] ggis, int sz) { 430 if (ggis == null) { 431 if (sz < 10) sz = 10; 432 return new GlyphGroupInfo[sz]; 433 } 434 if (sz <= ggis.length) 435 return ggis; 436 437 int nsz = ggis.length*2; 438 if (nsz < sz) nsz = sz; 439 return new GlyphGroupInfo[nsz]; 440 } 441 }; 442 | Popular Tags |