1 18 19 package org.apache.batik.extension.svg; 20 21 import java.awt.geom.Point2D ; 22 import java.awt.font.FontRenderContext ; 23 import java.text.AttributedCharacterIterator ; 24 import java.util.Iterator ; 25 import java.util.List ; 26 import java.util.LinkedList ; 27 28 import org.apache.batik.gvt.font.GVTFont; 29 import org.apache.batik.gvt.font.GVTGlyphVector; 30 import org.apache.batik.gvt.font.GVTLineMetrics; 31 import org.apache.batik.gvt.font.MultiGlyphVector; 32 import org.apache.batik.gvt.text.GlyphLayout; 33 34 import org.apache.batik.gvt.TextNode; 35 36 42 public class FlowExtGlyphLayout extends GlyphLayout { 43 44 public FlowExtGlyphLayout(AttributedCharacterIterator aci, 45 int [] charMap, 46 Point2D offset, 47 FontRenderContext frc) { 48 super(aci, charMap, offset, frc); 49 } 50 51 52 63 68 79 83 104 119 public static void textWrapTextChunk(AttributedCharacterIterator [] acis, 120 List chunkLayouts, 121 List flowRects) { 122 125 GVTGlyphVector [] gvs = new GVTGlyphVector[acis.length]; 129 List [] chunkLineInfos = new List [acis.length]; 130 GlyphIterator [] gis = new GlyphIterator [acis.length]; 131 Iterator clIter = chunkLayouts.iterator(); 132 133 Iterator flowRectsIter = flowRects.iterator(); 135 RegionInfo currentRegion = null; 137 float y0, x0, width, height=0; 138 if (flowRectsIter.hasNext()) { 139 currentRegion = (RegionInfo) flowRectsIter.next(); 140 height = (float) currentRegion.getHeight(); 141 } 142 143 boolean lineHeightRelative = true; 144 float lineHeight = 1.0f; 145 float nextLineMult = 0.0f; 146 float dy = 0.0f; 147 148 Point2D.Float verticalAlignOffset = new Point2D.Float (0,0); 150 151 153 float prevBotMargin = 0; 154 for (int chunk=0; clIter.hasNext(); chunk++) { 155 AttributedCharacterIterator aci = acis[chunk]; 157 if (currentRegion != null) 158 { 159 List extraP = (List )aci.getAttribute(FLOW_EMPTY_PARAGRAPH); 160 if (extraP != null) { 161 Iterator epi = extraP.iterator(); 162 while (epi.hasNext()) { 163 MarginInfo emi = (MarginInfo)epi.next(); 164 float inc = ((prevBotMargin > emi.getTopMargin()) 165 ? prevBotMargin 166 : emi.getTopMargin()); 167 if ((dy + inc <= height) && 168 !emi.isFlowRegionBreak()) { 169 dy += inc; 170 prevBotMargin = emi.getBottomMargin(); 171 } else { 172 if (!flowRectsIter.hasNext()) { 174 currentRegion = null; 175 break; } 177 178 currentRegion = (RegionInfo) flowRectsIter.next(); 180 height = (float) currentRegion.getHeight(); 181 verticalAlignOffset = new Point2D.Float (0,0); 183 184 dy = 0; 187 prevBotMargin = 0; 188 } 189 } 190 191 if (currentRegion == null) break; 192 } 193 } 194 195 List gvl = new LinkedList (); 196 List layouts = (List )clIter.next(); 197 Iterator iter = layouts.iterator(); 198 while (iter.hasNext()) { 199 GlyphLayout gl = (GlyphLayout)iter.next(); 200 gvl.add(gl.getGlyphVector()); 201 } 202 GVTGlyphVector gv = new MultiGlyphVector(gvl); 203 gvs[chunk] = gv; 204 int numGlyphs = gv.getNumGlyphs(); 205 206 208 aci.first(); 209 MarginInfo mi = (MarginInfo)aci.getAttribute(FLOW_PARAGRAPH); 210 if (mi == null) { 211 continue; 212 } 213 215 if (currentRegion == null) { 216 for(int idx=0; idx <numGlyphs; idx++) 217 gv.setGlyphVisible(idx, false); 218 continue; 219 } 220 221 float inc = ((prevBotMargin > mi.getTopMargin()) 222 ? prevBotMargin : mi.getTopMargin()); 223 if (dy + inc <= height) { 224 dy += inc; 225 } else { 226 if (!flowRectsIter.hasNext()) { 229 currentRegion = null; 230 break; } 232 233 currentRegion = (RegionInfo) flowRectsIter.next(); 235 height = (float) currentRegion.getHeight(); 236 verticalAlignOffset = new Point2D.Float (0,0); 238 239 dy = mi.getTopMargin(); 241 } 242 prevBotMargin = mi.getBottomMargin(); 243 244 float leftMargin = mi.getLeftMargin(); 245 float rightMargin = mi.getRightMargin(); 246 if (((GlyphLayout)layouts.get(0)).isLeftToRight()) { 247 leftMargin += mi.getIndent(); 248 } else { 249 rightMargin += mi.getIndent(); 250 } 251 252 x0 = (float) currentRegion.getX() + leftMargin; 253 y0 = (float) currentRegion.getY(); 254 width = (float) (currentRegion.getWidth() - 255 (leftMargin + rightMargin)); 256 height = (float) currentRegion.getHeight(); 257 258 List lineInfos = new LinkedList (); 259 chunkLineInfos[chunk] = lineInfos; 260 261 float prevDesc = 0.0f; 262 GlyphIterator gi = new GlyphIterator(aci, gv); 263 gis[chunk] = gi; 264 265 GlyphIterator breakGI = null, newBreakGI = null; 266 267 if (!gi.done() && !gi.isPrinting()) { 268 updateVerticalAlignOffset(verticalAlignOffset, 274 currentRegion, dy); 275 lineInfos.add(gi.newLine 276 (new Point2D.Float (x0, y0+dy), 277 width, true, verticalAlignOffset)); 278 } 279 280 281 GlyphIterator lineGI = gi.copy(); 282 boolean firstLine = true; 283 while (!gi.done()) { 284 boolean doBreak = false; 285 boolean partial = false; 286 287 if (gi.isPrinting() && (gi.getAdv() > width)) { 288 if (breakGI == null) { 289 if (!flowRectsIter.hasNext()) { 292 currentRegion = null; 293 gi = lineGI.copy(gi); 294 break; } 296 297 currentRegion = (RegionInfo) flowRectsIter.next(); 299 x0 = (float) currentRegion.getX() + leftMargin; 300 y0 = (float) currentRegion.getY(); 301 width = (float) (currentRegion.getWidth() - 302 (leftMargin+rightMargin)); 303 height = (float) currentRegion.getHeight(); 304 verticalAlignOffset = new Point2D.Float (0,0); 306 307 dy = firstLine ? mi.getTopMargin() : 0; 309 prevDesc = 0; 310 gi = lineGI.copy(gi); 311 continue; 312 } 313 314 gi = breakGI.copy(gi); 316 nextLineMult = 1; 317 doBreak = true; 318 partial = false; 319 } else if (gi.isLastChar()) { 320 nextLineMult = 1; 321 doBreak = true; 322 partial = true; 323 } 324 int lnBreaks = gi.getLineBreaks(); 325 if (lnBreaks != 0) { 326 if (doBreak) 327 nextLineMult -= 1; 328 nextLineMult += lnBreaks; 329 doBreak = true; 330 partial = true; 331 } 332 333 if (!doBreak) { 334 if ((gi.isBreakChar()) || 338 (breakGI == null) || 339 (!breakGI.isBreakChar())) { 340 newBreakGI = gi.copy(newBreakGI); 345 gi.nextChar(); 346 if (gi.getChar() != GlyphIterator.ZERO_WIDTH_JOINER) { 347 GlyphIterator tmpGI = breakGI; 348 breakGI = newBreakGI; 349 newBreakGI = tmpGI; 350 } 351 } else { 352 gi.nextChar(); 353 } 354 continue; 355 } 356 357 359 362 367 float lineSize = gi.getMaxAscent()+gi.getMaxDescent(); 370 float lineBoxHeight; 371 if (lineHeightRelative) 372 lineBoxHeight = gi.getMaxFontSize()*lineHeight; 373 else 374 lineBoxHeight = lineHeight; 375 float halfLeading = (lineBoxHeight-lineSize)/2; 376 377 float ladv = prevDesc + halfLeading + gi.getMaxAscent(); 378 float newDesc = halfLeading + gi.getMaxDescent(); 379 380 dy += ladv; 381 float bottomEdge = newDesc; 382 if (newDesc < gi.getMaxDescent()) 383 bottomEdge = gi.getMaxDescent(); 384 385 if ((dy + bottomEdge) > height) { 386 390 392 if (!flowRectsIter.hasNext()) { 393 currentRegion = null; 394 gi = lineGI.copy(gi); 395 break; } 397 398 float oldWidth = width; 400 401 currentRegion = (RegionInfo) flowRectsIter.next(); 403 x0 = (float) currentRegion.getX() + leftMargin; 404 y0 = (float) currentRegion.getY(); 405 width = (float)(currentRegion.getWidth() - 406 (leftMargin+rightMargin)); 407 height = (float) currentRegion.getHeight(); 408 verticalAlignOffset = new Point2D.Float (0,0); 410 411 dy = firstLine ? mi.getTopMargin() : 0; 413 prevDesc = 0; 414 416 if ((oldWidth > width) || (lnBreaks != 0)) { 417 gi = lineGI.copy(gi); 419 } 420 continue; 421 } 422 423 prevDesc = newDesc + (nextLineMult-1)*lineBoxHeight; 424 nextLineMult = 0f; 425 updateVerticalAlignOffset(verticalAlignOffset, 426 currentRegion, dy + bottomEdge); 427 lineInfos.add(gi.newLine 428 (new Point2D.Float (x0, y0 + dy), width, partial, 429 verticalAlignOffset)); 430 431 x0 -= leftMargin; 433 width += leftMargin+rightMargin; 434 435 leftMargin = mi.getLeftMargin(); 436 rightMargin = mi.getRightMargin(); 437 x0 += leftMargin; 438 width -= leftMargin+rightMargin; 439 440 firstLine = false; 441 lineGI = gi.copy(lineGI); 443 breakGI = null; 444 } 445 dy += prevDesc; 446 447 int idx = gi.getGlyphIndex(); 448 while(idx <numGlyphs) 449 gv.setGlyphVisible(idx++, false); 450 451 if (mi.isFlowRegionBreak()) { 452 currentRegion = null; 454 if (flowRectsIter.hasNext()) { 455 currentRegion = (RegionInfo) flowRectsIter.next(); 456 height = (float) currentRegion.getHeight(); 457 458 dy = 0; 461 prevBotMargin = 0; 462 verticalAlignOffset = new Point2D.Float (0,0); 463 } 464 } 465 } 466 467 for (int chunk=0; chunk < acis.length; chunk++) { 468 List lineInfos = chunkLineInfos[chunk]; 469 if (lineInfos == null) continue; 470 471 AttributedCharacterIterator aci = acis[chunk]; 472 aci.first(); 473 MarginInfo mi = (MarginInfo)aci.getAttribute(FLOW_PARAGRAPH); 474 if (mi == null) { 475 continue; 476 } 477 int justification = mi.getJustification(); 478 479 GVTGlyphVector gv = gvs[chunk]; 480 if (gv == null) break; 481 482 GlyphIterator gi = gis[chunk]; 483 484 layoutChunk(gv, gi.getOrigin(), justification, lineInfos); 485 } 486 } 487 488 489 507 public static void updateVerticalAlignOffset 508 (Point2D.Float verticalAlignOffset, 509 RegionInfo region, float maxDescent) 510 { 511 float freeSpace = (float)region.getHeight() - maxDescent; 512 verticalAlignOffset.setLocation 513 (0, region.getVerticalAlignment() * freeSpace); 514 } 515 516 public static void layoutChunk(GVTGlyphVector gv, Point2D origin, 517 int justification, 518 List lineInfos) { 519 Iterator lInfoIter = lineInfos.iterator(); 520 int numGlyphs = gv.getNumGlyphs(); 521 float [] gp = gv.getGlyphPositions(0, numGlyphs+1, null); 522 Point2D.Float lineLoc = null; 523 float lineAdv = 0; 524 float lineVAdv = 0; 525 526 float xOrig=(float)origin.getX(); 527 float yOrig=(float)origin.getY(); 528 529 float xScale=1; 530 float xAdj=0; 531 float charW=0; 532 float lineWidth=0; 533 boolean partial = false; 534 float verticalAlignOffset = 0; 535 536 int lineEnd = 0; 539 int i; 540 Point2D.Float pos = new Point2D.Float (); 541 for (i =0; i<numGlyphs; i++) { 542 if (i == lineEnd) { 543 545 xOrig += lineAdv; 547 548 if (!lInfoIter.hasNext()) 550 break; 551 LineInfo li = (LineInfo)lInfoIter.next(); 552 554 lineEnd = li.getEndIdx(); 555 lineLoc = li.getLocation(); 556 lineAdv = li.getAdvance(); 557 lineVAdv = li.getVisualAdvance(); 558 charW = li.getLastCharWidth(); 559 lineWidth = li.getLineWidth(); 560 partial = li.isPartialLine(); 561 verticalAlignOffset = li.getVerticalAlignOffset().y; 562 563 xAdj = 0; 564 xScale = 1; 565 switch (justification) { 567 case 0: default: break; case 1: xAdj = (lineWidth - lineVAdv) / 2; 570 break; 571 case 2: xAdj = lineWidth - lineVAdv; 573 break; 574 case 3: if ((!partial) && (lineEnd != i+1)) { 576 xScale = (lineWidth-charW)/(lineVAdv-charW); 579 } 580 break; 581 } 582 } 583 pos.x = lineLoc.x + (gp[2*i] -xOrig)*xScale+xAdj; 584 pos.y = lineLoc.y + ((gp[2 * i + 1] - yOrig) + 585 verticalAlignOffset); 586 gv.setGlyphPosition(i, pos); 587 } 588 589 pos.x = xOrig; 590 pos.y = yOrig; 591 if (lineLoc != null) { 592 pos.x = lineLoc.x + (gp[2*i] -xOrig)*xScale+xAdj; 593 pos.y = lineLoc.y + (gp[2 * i + 1] - yOrig) + verticalAlignOffset; 594 } 595 gv.setGlyphPosition(i, pos); 596 } 597 } 598 | Popular Tags |