1 11 package org.eclipse.swt.graphics; 12 13 import org.eclipse.swt.internal.*; 14 import org.eclipse.swt.internal.gdip.*; 15 import org.eclipse.swt.internal.win32.*; 16 import org.eclipse.swt.*; 17 18 33 public final class TextLayout extends Resource { 34 Font font; 35 String text, segmentsText; 36 int lineSpacing; 37 int ascent, descent; 38 int alignment; 39 int wrapWidth; 40 int orientation; 41 int indent; 42 boolean justify; 43 int[] tabs; 44 int[] segments; 45 StyleItem[] styles; 46 47 StyleItem[] allRuns; 48 StyleItem[][] runs; 49 int[] lineOffset, lineY, lineWidth; 50 int mLangFontLink2; 51 52 static final char LTR_MARK = '\u200E', RTL_MARK = '\u200F'; 53 static final int SCRIPT_VISATTR_SIZEOF = 2; 54 static final int GOFFSET_SIZEOF = 8; 55 static final byte[] CLSID_CMultiLanguage = new byte[16]; 56 static final byte[] IID_IMLangFontLink2 = new byte[16]; 57 static { 58 OS.IIDFromString("{275c23e2-3747-11d0-9fea-00aa003f8646}\0".toCharArray(), CLSID_CMultiLanguage); 59 OS.IIDFromString("{DCCFC162-2B38-11d2-B7EC-00C04F8F5D9A}\0".toCharArray(), IID_IMLangFontLink2); 60 } 61 62 class StyleItem { 63 TextStyle style; 64 int start, length; 65 boolean lineBreak, softBreak, tab; 66 67 68 SCRIPT_ANALYSIS analysis; 69 int psc = 0; 70 71 72 int glyphs; 73 int glyphCount; 74 int clusters; 75 int visAttrs; 76 77 78 int advances; 79 int goffsets; 80 int width; 81 int ascent; 82 int descent; 83 int leading; 84 int x; 85 86 87 int justify; 88 89 90 int psla; 91 92 int fallbackFont; 93 94 void free() { 95 int hHeap = OS.GetProcessHeap(); 96 if (psc != 0) { 97 OS.ScriptFreeCache (psc); 98 OS.HeapFree(hHeap, 0, psc); 99 psc = 0; 100 } 101 if (glyphs != 0) { 102 OS.HeapFree(hHeap, 0, glyphs); 103 glyphs = 0; 104 glyphCount = 0; 105 } 106 if (clusters != 0) { 107 OS.HeapFree(hHeap, 0, clusters); 108 clusters = 0; 109 } 110 if (visAttrs != 0) { 111 OS.HeapFree(hHeap, 0, visAttrs); 112 visAttrs = 0; 113 } 114 if (advances != 0) { 115 OS.HeapFree(hHeap, 0, advances); 116 advances = 0; 117 } 118 if (goffsets != 0) { 119 OS.HeapFree(hHeap, 0, goffsets); 120 goffsets = 0; 121 } 122 if (justify != 0) { 123 OS.HeapFree(hHeap, 0, justify); 124 justify = 0; 125 } 126 if (psla != 0) { 127 OS.HeapFree(hHeap, 0, psla); 128 psla = 0; 129 } 130 if (fallbackFont != 0) { 131 if (mLangFontLink2 != 0) { 132 133 OS.VtblCall(8, mLangFontLink2, fallbackFont); 134 } 135 fallbackFont = 0; 136 } 137 width = ascent = descent = x = 0; 138 lineBreak = softBreak = false; 139 } 140 public String toString () { 141 return "StyleItem {" + start + ", " + style + "}"; 142 } 143 } 144 145 159 public TextLayout (Device device) { 160 if (device == null) device = Device.getDevice(); 161 if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 162 this.device = device; 163 wrapWidth = ascent = descent = -1; 164 lineSpacing = 0; 165 orientation = SWT.LEFT_TO_RIGHT; 166 styles = new StyleItem[2]; 167 styles[0] = new StyleItem(); 168 styles[1] = new StyleItem(); 169 text = ""; int[] ppv = new int[1]; 171 OS.OleInitialize(0); 172 if (OS.CoCreateInstance(CLSID_CMultiLanguage, 0, OS.CLSCTX_INPROC_SERVER, IID_IMLangFontLink2, ppv) == OS.S_OK) { 173 mLangFontLink2 = ppv[0]; 174 } 175 if (device.tracking) device.new_Object(this); 176 } 177 178 void breakRun(StyleItem run) { 179 if (run.psla != 0) return; 180 char[] chars = new char[run.length]; 181 segmentsText.getChars(run.start, run.start + run.length, chars, 0); 182 int hHeap = OS.GetProcessHeap(); 183 run.psla = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_LOGATTR.sizeof * chars.length); 184 if (run.psla == 0) SWT.error(SWT.ERROR_NO_HANDLES); 185 OS.ScriptBreak(chars, chars.length, run.analysis, run.psla); 186 } 187 188 void checkItem (int hDC, StyleItem item) { 189 if (item.fallbackFont != 0) { 190 197 LOGFONT logFont = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA(); 198 if (OS.GetObject(item.fallbackFont, LOGFONT.sizeof, logFont) == 0) { 199 item.free(); 200 OS.SelectObject(hDC, getItemFont(item)); 201 shape(hDC, item); 202 } 203 } 204 } 205 206 void checkLayout () { 207 if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); 208 } 209 210 214 void computeRuns (GC gc) { 215 if (runs != null) return; 216 int hDC = gc != null ? gc.handle : device.internal_new_GC(null); 217 int srcHdc = OS.CreateCompatibleDC(hDC); 218 allRuns = itemize(); 219 for (int i=0; i<allRuns.length - 1; i++) { 220 StyleItem run = allRuns[i]; 221 OS.SelectObject(srcHdc, getItemFont(run)); 222 shape(srcHdc, run); 223 } 224 SCRIPT_LOGATTR logAttr = new SCRIPT_LOGATTR(); 225 SCRIPT_PROPERTIES properties = new SCRIPT_PROPERTIES(); 226 int lineWidth = indent, lineStart = 0, lineCount = 1; 227 for (int i=0; i<allRuns.length - 1; i++) { 228 StyleItem run = allRuns[i]; 229 if (run.length == 1) { 230 char ch = segmentsText.charAt(run.start); 231 switch (ch) { 232 case '\t': { 233 run.tab = true; 234 if (tabs == null) break; 235 int tabsLength = tabs.length, j; 236 for (j = 0; j < tabsLength; j++) { 237 if (tabs[j] > lineWidth) { 238 run.width = tabs[j] - lineWidth; 239 break; 240 } 241 } 242 if (j == tabsLength) { 243 int tabX = tabs[tabsLength-1]; 244 int lastTabWidth = tabsLength > 1 ? tabs[tabsLength-1] - tabs[tabsLength-2] : tabs[0]; 245 if (lastTabWidth > 0) { 246 while (tabX <= lineWidth) tabX += lastTabWidth; 247 run.width = tabX - lineWidth; 248 } 249 } 250 break; 251 } 252 case '\n': { 253 run.lineBreak = true; 254 break; 255 } 256 case '\r': { 257 run.lineBreak = true; 258 StyleItem next = allRuns[i + 1]; 259 if (next.length != 0 && segmentsText.charAt(next.start) == '\n') { 260 run.length += 1; 261 next.free(); 262 i++; 263 } 264 break; 265 } 266 } 267 } 268 if (wrapWidth != -1 && lineWidth + run.width > wrapWidth && !run.tab) { 269 int start = 0; 270 int[] piDx = new int[run.length]; 271 if (run.style != null && run.style.metrics != null) { 272 piDx[0] = run.width; 273 } else { 274 OS.ScriptGetLogicalWidths(run.analysis, run.length, run.glyphCount, run.advances, run.clusters, run.visAttrs, piDx); 275 } 276 int width = 0, maxWidth = wrapWidth - lineWidth; 277 while (width + piDx[start] < maxWidth) { 278 width += piDx[start++]; 279 } 280 int firstStart = start; 281 int firstIndice = i; 282 while (i >= lineStart) { 283 breakRun(run); 284 while (start >= 0) { 285 OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); 286 if (logAttr.fSoftBreak || logAttr.fWhiteSpace) break; 287 start--; 288 } 289 290 295 if (start == 0 && i != lineStart && !run.tab) { 296 if (logAttr.fSoftBreak && !logAttr.fWhiteSpace) { 297 OS.MoveMemory(properties, device.scripts[run.analysis.eScript], SCRIPT_PROPERTIES.sizeof); 298 int langID = properties.langid; 299 StyleItem pRun = allRuns[i - 1]; 300 OS.MoveMemory(properties, device.scripts[pRun.analysis.eScript], SCRIPT_PROPERTIES.sizeof); 301 if (properties.langid == langID || langID == OS.LANG_NEUTRAL || properties.langid == OS.LANG_NEUTRAL) { 302 breakRun(pRun); 303 OS.MoveMemory(logAttr, pRun.psla + ((pRun.length - 1) * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); 304 if (!logAttr.fWhiteSpace) start = -1; 305 } 306 } 307 } 308 if (start >= 0 || i == lineStart) break; 309 run = allRuns[--i]; 310 start = run.length - 1; 311 } 312 if (start == 0 && i != lineStart && !run.tab) { 313 run = allRuns[--i]; 314 } else if (start <= 0 && i == lineStart) { 315 i = firstIndice; 316 run = allRuns[i]; 317 start = Math.max(1, firstStart); 318 } 319 breakRun(run); 320 while (start < run.length) { 321 OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); 322 if (!logAttr.fWhiteSpace) break; 323 start++; 324 } 325 if (0 < start && start < run.length) { 326 StyleItem newRun = new StyleItem(); 327 newRun.start = run.start + start; 328 newRun.length = run.length - start; 329 newRun.style = run.style; 330 newRun.analysis = run.analysis; 331 run.free(); 332 run.length = start; 333 OS.SelectObject(srcHdc, getItemFont(run)); 334 shape (srcHdc, run); 335 OS.SelectObject(srcHdc, getItemFont(newRun)); 336 shape (srcHdc, newRun); 337 StyleItem[] newAllRuns = new StyleItem[allRuns.length + 1]; 338 System.arraycopy(allRuns, 0, newAllRuns, 0, i + 1); 339 System.arraycopy(allRuns, i + 1, newAllRuns, i + 2, allRuns.length - i - 1); 340 allRuns = newAllRuns; 341 allRuns[i + 1] = newRun; 342 } 343 if (i != allRuns.length - 2) { 344 run.softBreak = run.lineBreak = true; 345 } 346 } 347 lineWidth += run.width; 348 if (run.lineBreak) { 349 lineStart = i + 1; 350 lineWidth = run.softBreak ? 0 : indent; 351 lineCount++; 352 } 353 } 354 lineWidth = 0; 355 runs = new StyleItem[lineCount][]; 356 lineOffset = new int[lineCount + 1]; 357 lineY = new int[lineCount + 1]; 358 this.lineWidth = new int[lineCount]; 359 int lineRunCount = 0, line = 0; 360 int ascent = Math.max(0, this.ascent); 361 int descent = Math.max(0, this.descent); 362 StyleItem[] lineRuns = new StyleItem[allRuns.length]; 363 for (int i=0; i<allRuns.length; i++) { 364 StyleItem run = allRuns[i]; 365 lineRuns[lineRunCount++] = run; 366 lineWidth += run.width; 367 ascent = Math.max(ascent, run.ascent); 368 descent = Math.max(descent, run.descent); 369 if (run.lineBreak || i == allRuns.length - 1) { 370 371 if (lineRunCount == 1 && i == allRuns.length - 1) { 372 TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA(); 373 OS.SelectObject(srcHdc, getItemFont(run)); 374 OS.GetTextMetrics(srcHdc, lptm); 375 run.ascent = lptm.tmAscent; 376 run.descent = lptm.tmDescent; 377 ascent = Math.max(ascent, run.ascent); 378 descent = Math.max(descent, run.descent); 379 } 380 runs[line] = new StyleItem[lineRunCount]; 381 System.arraycopy(lineRuns, 0, runs[line], 0, lineRunCount); 382 383 if (justify && wrapWidth != -1 && run.softBreak && lineWidth > 0) { 384 if (line == 0) { 385 lineWidth += indent; 386 } else { 387 StyleItem[] previousLine = runs[line - 1]; 388 StyleItem previousRun = previousLine[previousLine.length - 1]; 389 if (previousRun.lineBreak && !previousRun.softBreak) { 390 lineWidth += indent; 391 } 392 } 393 int hHeap = OS.GetProcessHeap(); 394 int newLineWidth = 0; 395 for (int j = 0; j < runs[line].length; j++) { 396 StyleItem item = runs[line][j]; 397 int iDx = item.width * wrapWidth / lineWidth; 398 if (iDx != item.width) { 399 item.justify = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, item.glyphCount * 4); 400 if (item.justify == 0) SWT.error(SWT.ERROR_NO_HANDLES); 401 OS.ScriptJustify(item.visAttrs, item.advances, item.glyphCount, iDx - item.width, 2, item.justify); 402 item.width = iDx; 403 } 404 newLineWidth += item.width; 405 } 406 lineWidth = newLineWidth; 407 } 408 this.lineWidth[line] = lineWidth; 409 410 StyleItem lastRun = runs[line][lineRunCount - 1]; 411 int lastOffset = lastRun.start + lastRun.length; 412 runs[line] = reorder(runs[line], i == allRuns.length - 1); 413 lastRun = runs[line][lineRunCount - 1]; 414 if (run.softBreak && run != lastRun) { 415 run.softBreak = run.lineBreak = false; 416 lastRun.softBreak = lastRun.lineBreak = true; 417 } 418 419 lineWidth = getLineIndent(line); 420 for (int j = 0; j < runs[line].length; j++) { 421 runs[line][j].x = lineWidth; 422 lineWidth += runs[line][j].width; 423 } 424 line++; 425 lineY[line] = lineY[line - 1] + ascent + descent + lineSpacing; 426 lineOffset[line] = lastOffset; 427 lineRunCount = lineWidth = 0; 428 ascent = Math.max(0, this.ascent); 429 descent = Math.max(0, this.descent); 430 } 431 } 432 if (srcHdc != 0) OS.DeleteDC(srcHdc); 433 if (gc == null) device.internal_dispose_GC(hDC, null); 434 } 435 436 440 public void dispose () { 441 if (device == null) return; 442 freeRuns(); 443 font = null; 444 text = null; 445 segmentsText = null; 446 tabs = null; 447 styles = null; 448 runs = null; 449 lineOffset = null; 450 lineY = null; 451 lineWidth = null; 452 if (mLangFontLink2 != 0) { 453 454 OS.VtblCall(2, mLangFontLink2); 455 mLangFontLink2 = 0; 456 } 457 OS.OleUninitialize(); 458 if (device.tracking) device.dispose_Object(this); 459 device = null; 460 } 461 462 477 public void draw (GC gc, int x, int y) { 478 draw(gc, x, y, -1, -1, null, null); 479 } 480 481 500 public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground) { 501 draw(gc, x, y, selectionStart, selectionEnd, selectionForeground, selectionBackground, 0); 502 } 503 504 531 public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground, int flags) { 532 checkLayout(); 533 computeRuns(gc); 534 if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 535 if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 536 if (selectionForeground != null && selectionForeground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 537 if (selectionBackground != null && selectionBackground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 538 int length = text.length(); 539 if (length == 0 && flags == 0) return; 540 int hdc = gc.handle; 541 Rectangle clip = gc.getClipping(); 542 GCData data = gc.data; 543 int gdipGraphics = data.gdipGraphics; 544 int foreground = data.foreground; 545 int alpha = data.alpha; 546 boolean gdip = gdipGraphics != 0 && (alpha != 0xFF || data.foregroundPattern != null); 547 int clipRgn = 0; 548 float[] lpXform = null; 549 Rect gdipRect = new Rect(); 550 if (gdipGraphics != 0 && !gdip) { 551 int matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0); 552 if (matrix == 0) SWT.error(SWT.ERROR_NO_HANDLES); 553 Gdip.Graphics_GetTransform(gdipGraphics, matrix); 554 int identity = gc.identity(); 555 Gdip.Matrix_Invert(identity); 556 Gdip.Matrix_Multiply(matrix, identity, Gdip.MatrixOrderAppend); 557 Gdip.Matrix_delete(identity); 558 if (!Gdip.Matrix_IsIdentity(matrix)) { 559 lpXform = new float[6]; 560 Gdip.Matrix_GetElements(matrix, lpXform); 561 } 562 Gdip.Matrix_delete(matrix); 563 if ((data.style & SWT.MIRRORED) != 0 && lpXform != null) { 564 gdip = true; 565 lpXform = null; 566 } else { 567 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone); 568 int rgn = Gdip.Region_new(); 569 Gdip.Graphics_GetClip(gdipGraphics, rgn); 570 if (!Gdip.Region_IsInfinite(rgn, gdipGraphics)) { 571 clipRgn = Gdip.Region_GetHRGN(rgn, gdipGraphics); 572 } 573 Gdip.Region_delete(rgn); 574 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); 575 hdc = Gdip.Graphics_GetHDC(gdipGraphics); 576 } 577 } 578 int foregroundBrush = 0, state = 0; 579 if (gdip) { 580 gc.checkGC(GC.FOREGROUND); 581 foregroundBrush = gc.getFgBrush(); 582 } else { 583 state = OS.SaveDC(hdc); 584 if ((data.style & SWT.MIRRORED) != 0) { 585 OS.SetLayout(hdc, OS.GetLayout(hdc) | OS.LAYOUT_RTL); 586 } 587 if (lpXform != null) { 588 OS.SetGraphicsMode(hdc, OS.GM_ADVANCED); 589 OS.SetWorldTransform(hdc, lpXform); 590 } 591 if (clipRgn != 0) { 592 OS.SelectClipRgn(hdc, clipRgn); 593 OS.DeleteObject(clipRgn); 594 } 595 } 596 boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1; 597 if (hasSelection || (flags & SWT.LAST_LINE_SELECTION) != 0) { 598 selectionStart = Math.min(Math.max(0, selectionStart), length - 1); 599 selectionEnd = Math.min(Math.max(0, selectionEnd), length - 1); 600 if (selectionForeground == null) selectionForeground = device.getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT); 601 if (selectionBackground == null) selectionBackground = device.getSystemColor(SWT.COLOR_LIST_SELECTION); 602 selectionStart = translateOffset(selectionStart); 603 selectionEnd = translateOffset(selectionEnd); 604 } 605 RECT rect = new RECT(); 606 int selBrush = 0, selPen = 0, selBrushFg = 0; 607 if (hasSelection || (flags & SWT.LAST_LINE_SELECTION) != 0) { 608 if (gdip) { 609 int bg = selectionBackground.handle; 610 int argb = ((alpha & 0xFF) << 24) | ((bg >> 16) & 0xFF) | (bg & 0xFF00) | ((bg & 0xFF) << 16); 611 int color = Gdip.Color_new(argb); 612 selBrush = Gdip.SolidBrush_new(color); 613 Gdip.Color_delete(color); 614 int fg = selectionForeground.handle; 615 argb = ((alpha & 0xFF) << 24) | ((fg >> 16) & 0xFF) | (fg & 0xFF00) | ((fg & 0xFF) << 16); 616 color = Gdip.Color_new(argb); 617 selBrushFg = Gdip.SolidBrush_new(color); 618 selPen = Gdip.Pen_new(selBrushFg, 1); 619 Gdip.Color_delete(color); 620 } else { 621 selBrush = OS.CreateSolidBrush(selectionBackground.handle); 622 selPen = OS.CreatePen(OS.PS_SOLID, 1, selectionForeground.handle); 623 } 624 } 625 int offset = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? -1 : 0; 626 OS.SetBkMode(hdc, OS.TRANSPARENT); 627 for (int line=0; line<runs.length; line++) { 628 int drawX = x + getLineIndent(line); 629 int drawY = y + lineY[line]; 630 StyleItem[] lineRuns = runs[line]; 631 int lineHeight = lineY[line+1] - lineY[line]; 632 if (flags != 0 && (hasSelection || (flags & SWT.LAST_LINE_SELECTION) != 0)) { 633 boolean extents = false; 634 if (line == runs.length - 1 && (flags & SWT.LAST_LINE_SELECTION) != 0) { 635 extents = true; 636 } else { 637 StyleItem run = lineRuns[lineRuns.length - 1]; 638 if (run.lineBreak && !run.softBreak) { 639 if (selectionStart <= run.start && run.start <= selectionEnd) extents = true; 640 } else { 641 int endOffset = run.start + run.length - 1; 642 if (selectionStart <= endOffset && endOffset < selectionEnd && (flags & SWT.FULL_SELECTION) != 0) { 643 extents = true; 644 } 645 } 646 } 647 if (extents) { 648 int width; 649 if ((flags & SWT.FULL_SELECTION) != 0) { 650 width = OS.IsWin95 ? 0x7FFF : 0x6FFFFFF; 651 } else { 652 width = (lineHeight - lineSpacing) / 3; 653 } 654 if (gdip) { 655 Gdip.Graphics_FillRectangle(gdipGraphics, selBrush, drawX + lineWidth[line], drawY, width, lineHeight - lineSpacing); 656 } else { 657 OS.SelectObject(hdc, selBrush); 658 OS.PatBlt(hdc, drawX + lineWidth[line], drawY, width, lineHeight - lineSpacing, OS.PATCOPY); 659 } 660 } 661 } 662 if (drawX > clip.x + clip.width) continue; 663 if (drawX + lineWidth[line] < clip.x) continue; 664 int baseline = Math.max(0, this.ascent); 665 for (int i = 0; i < lineRuns.length; i++) { 666 baseline = Math.max(baseline, lineRuns[i].ascent); 667 } 668 int alignmentX = drawX; 669 for (int i = 0; i < lineRuns.length; i++) { 670 StyleItem run = lineRuns[i]; 671 if (run.length == 0) continue; 672 if (drawX > clip.x + clip.width) break; 673 if (drawX + run.width >= clip.x) { 674 if (!run.lineBreak || run.softBreak) { 675 int end = run.start + run.length - 1; 676 boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; 677 if (fullSelection) { 678 if (gdip) { 679 Gdip.Graphics_FillRectangle(gdipGraphics, selBrush, drawX, drawY, run.width, lineHeight - lineSpacing); 680 } else { 681 OS.SelectObject(hdc, selBrush); 682 OS.PatBlt(hdc, drawX, drawY, run.width, lineHeight - lineSpacing, OS.PATCOPY); 683 } 684 } else { 685 if (run.style != null && run.style.background != null) { 686 int bg = run.style.background.handle; 687 int drawRunY = drawY + (baseline - run.ascent); 688 if (gdip) { 689 int argb = ((alpha & 0xFF) << 24) | ((bg >> 16) & 0xFF) | (bg & 0xFF00) | ((bg & 0xFF) << 16); 690 int color = Gdip.Color_new(argb); 691 int brush = Gdip.SolidBrush_new(color); 692 Gdip.Graphics_FillRectangle(gdipGraphics, brush, drawX, drawRunY, run.width, run.ascent + run.descent); 693 Gdip.Color_delete(color); 694 Gdip.SolidBrush_delete(brush); 695 } else { 696 int hBrush = OS.CreateSolidBrush (bg); 697 int oldBrush = OS.SelectObject(hdc, hBrush); 698 OS.PatBlt(hdc, drawX, drawRunY, run.width, run.ascent + run.descent, OS.PATCOPY); 699 OS.SelectObject(hdc, oldBrush); 700 OS.DeleteObject(hBrush); 701 } 702 } 703 boolean partialSelection = hasSelection && !(selectionStart > end || run.start > selectionEnd); 704 if (partialSelection) { 705 int selStart = Math.max(selectionStart, run.start) - run.start; 706 int selEnd = Math.min(selectionEnd, end) - run.start; 707 int cChars = run.length; 708 int gGlyphs = run.glyphCount; 709 int[] piX = new int[1]; 710 int advances = run.justify != 0 ? run.justify : run.advances; 711 OS.ScriptCPtoX(selStart, false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX); 712 int runX = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - piX[0] : piX[0]; 713 rect.left = drawX + runX; 714 rect.top = drawY; 715 OS.ScriptCPtoX(selEnd, true, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX); 716 runX = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - piX[0] : piX[0]; 717 rect.right = drawX + runX; 718 rect.bottom = drawY + lineHeight - lineSpacing; 719 if (gdip) { 720 Gdip.Graphics_FillRectangle(gdipGraphics, selBrush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top); 721 } else { 722 OS.SelectObject(hdc, selBrush); 723 OS.PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY); 724 } 725 } 726 } 727 } 728 } 729 drawX += run.width; 730 } 731 drawX = alignmentX; 732 for (int i = 0; i < lineRuns.length; i++) { 733 StyleItem run = lineRuns[i]; 734 if (run.length == 0) continue; 735 if (drawX > clip.x + clip.width) break; 736 if (drawX + run.width >= clip.x) { 737 if (!run.tab && (!run.lineBreak || run.softBreak) && !(run.style != null && run.style.metrics != null)) { 738 int end = run.start + run.length - 1; 739 boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end; 740 boolean partialSelection = hasSelection && !fullSelection && !(selectionStart > end || run.start > selectionEnd); 741 checkItem(hdc, run); 742 OS.SelectObject(hdc, getItemFont(run)); 743 int drawRunY = drawY + (baseline - run.ascent); 744 if (partialSelection) { 745 int selStart = Math.max(selectionStart, run.start) - run.start; 746 int selEnd = Math.min(selectionEnd, end) - run.start; 747 int cChars = run.length; 748 int gGlyphs = run.glyphCount; 749 int[] piX = new int[1]; 750 int advances = run.justify != 0 ? run.justify : run.advances; 751 OS.ScriptCPtoX(selStart, false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX); 752 int runX = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - piX[0] : piX[0]; 753 rect.left = drawX + runX; 754 rect.top = drawY; 755 OS.ScriptCPtoX(selEnd, true, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX); 756 runX = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - piX[0] : piX[0]; 757 rect.right = drawX + runX; 758 rect.bottom = drawY + lineHeight; 759 } 760 if (gdip) { 761 OS.BeginPath(hdc); 762 OS.ScriptTextOut(hdc, run.psc, drawX, drawRunY, 0, null, run.analysis , 0, 0, run.glyphs, run.glyphCount, run.advances, run.justify, run.goffsets); 763 OS.EndPath(hdc); 764 int count = OS.GetPath(hdc, null, null, 0); 765 int[] points = new int[count*2]; 766 byte[] types = new byte[count]; 767 OS.GetPath(hdc, points, types, count); 768 for (int typeIndex = 0; typeIndex < types.length; typeIndex++) { 769 int newType = 0; 770 int type = types[typeIndex] & 0xFF; 771 switch (type & ~OS.PT_CLOSEFIGURE) { 772 case OS.PT_MOVETO: newType = Gdip.PathPointTypeStart; break; 773 case OS.PT_LINETO: newType = Gdip.PathPointTypeLine; break; 774 case OS.PT_BEZIERTO: newType = Gdip.PathPointTypeBezier; break; 775 } 776 if ((type & OS.PT_CLOSEFIGURE) != 0) newType |= Gdip.PathPointTypeCloseSubpath; 777 types[typeIndex] = (byte)newType; 778 } 779 int path = Gdip.GraphicsPath_new(points, types, count, Gdip.FillModeAlternate); 780 if (path == 0) SWT.error(SWT.ERROR_NO_HANDLES); 781 int brush = foregroundBrush; 782 if (fullSelection) { 783 brush = selBrushFg; 784 } else { 785 if (run.style != null && run.style.foreground != null) { 786 int fg = run.style.foreground.handle; 787 int argb = ((alpha & 0xFF) << 24) | ((fg >> 16) & 0xFF) | (fg & 0xFF00) | ((fg & 0xFF) << 16); 788 int color = Gdip.Color_new(argb); 789 brush = Gdip.SolidBrush_new(color); 790 Gdip.Color_delete(color); 791 } 792 } 793 int gstate = 0; 794 if (partialSelection) { 795 gdipRect.X = rect.left; 796 gdipRect.Y = rect.top; 797 gdipRect.Width = rect.right - rect.left; 798 gdipRect.Height = rect.bottom - rect.top; 799 gstate = Gdip.Graphics_Save(gdipGraphics); 800 Gdip.Graphics_SetClip(gdipGraphics, gdipRect, Gdip.CombineModeExclude); 801 } 802 int antialias = Gdip.Graphics_GetSmoothingMode(gdipGraphics), textAntialias = 0; 803 int mode = Gdip.Graphics_GetTextRenderingHint(data.gdipGraphics); 804 switch (mode) { 805 case Gdip.TextRenderingHintSystemDefault: textAntialias = Gdip.SmoothingModeAntiAlias; break; 806 case Gdip.TextRenderingHintSingleBitPerPixel: 807 case Gdip.TextRenderingHintSingleBitPerPixelGridFit: textAntialias = Gdip.SmoothingModeNone; break; 808 case Gdip.TextRenderingHintAntiAlias: 809 case Gdip.TextRenderingHintAntiAliasGridFit: 810 case Gdip.TextRenderingHintClearTypeGridFit: textAntialias = Gdip.SmoothingModeAntiAlias; break; 811 } 812 Gdip.Graphics_SetSmoothingMode(gdipGraphics, textAntialias); 813 int gstate2 = 0; 814 if ((data.style & SWT.MIRRORED) != 0) { 815 gstate2 = Gdip.Graphics_Save(gdipGraphics); 816 Gdip.Graphics_ScaleTransform(gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend); 817 Gdip.Graphics_TranslateTransform(gdipGraphics, -2 * drawX - run.width, 0, Gdip.MatrixOrderPrepend); 818 } 819 Gdip.Graphics_FillPath(gdipGraphics, brush, path); 820 if ((data.style & SWT.MIRRORED) != 0) { 821 Gdip.Graphics_Restore(gdipGraphics, gstate2); 822 } 823 Gdip.Graphics_SetSmoothingMode(gdipGraphics, antialias); 824 if (run.style != null && (run.style.underline || run.style.strikeout)) { 825 int newPen = hasSelection ? selPen : Gdip.Pen_new(brush, 1); 826 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone); 827 if (run.style.underline) { 828 int underlineY = drawY + baseline + 1 - run.style.rise; 829 Gdip.Graphics_DrawLine(gdipGraphics, newPen, drawX, underlineY, drawX + run.width, underlineY); 830 } 831 if (run.style.strikeout) { 832 int strikeoutY = drawRunY + run.leading + (run.ascent - run.style.rise) / 2; 833 Gdip.Graphics_DrawLine(gdipGraphics, newPen, drawX, strikeoutY, drawX + run.width, strikeoutY); 834 } 835 if (newPen != selPen) Gdip.Pen_delete(newPen); 836 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); 837 } 838 if (partialSelection) { 839 Gdip.Graphics_Restore(gdipGraphics, gstate); 840 gstate = Gdip.Graphics_Save(gdipGraphics); 841 Gdip.Graphics_SetClip(gdipGraphics, gdipRect, Gdip.CombineModeIntersect); 842 Gdip.Graphics_SetSmoothingMode(gdipGraphics, textAntialias); 843 Gdip.Graphics_FillPath(gdipGraphics, selBrushFg, path); 844 Gdip.Graphics_SetSmoothingMode(gdipGraphics, antialias); 845 if (run.style != null && (run.style.underline || run.style.strikeout)) { 846 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone); 847 if (run.style.underline) { 848 int underlineY = drawY + baseline + 1 - run.style.rise; 849 Gdip.Graphics_DrawLine(gdipGraphics, selPen, rect.left, underlineY, rect.right, underlineY); 850 } 851 if (run.style.strikeout) { 852 int strikeoutY = drawRunY + run.leading + (run.ascent - run.style.rise) / 2; 853 Gdip.Graphics_DrawLine(gdipGraphics, selPen, rect.left, strikeoutY, rect.right, strikeoutY); 854 } 855 Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf); 856 } 857 Gdip.Graphics_Restore(gdipGraphics, gstate); 858 } 859 Gdip.GraphicsPath_delete(path); 860 if (brush != selBrushFg && brush != foregroundBrush) Gdip.SolidBrush_delete(brush); 861 } else { 862 int fg = foreground; 863 if (fullSelection) { 864 fg = selectionForeground.handle; 865 } else { 866 if (run.style != null && run.style.foreground != null) fg = run.style.foreground.handle; 867 } 868 OS.SetTextColor(hdc, fg); 869 OS.ScriptTextOut(hdc, run.psc, drawX + offset, drawRunY, 0, null, run.analysis , 0, 0, run.glyphs, run.glyphCount, run.advances, run.justify, run.goffsets); 870 if (run.style != null && (run.style.underline || run.style.strikeout)) { 871 int newPen = hasSelection && fg == selectionForeground.handle ? selPen : OS.CreatePen(OS.PS_SOLID, 1, fg); 872 int oldPen = OS.SelectObject(hdc, newPen); 873 if (run.style.underline) { 874 int underlineY = drawY + baseline + 1 - run.style.rise; 875 OS.MoveToEx(hdc, drawX, underlineY, 0); 876 OS.LineTo(hdc, drawX + run.width, underlineY); 877 } 878 if (run.style.strikeout) { 879 int strikeoutY = drawRunY + run.leading + (run.ascent - run.style.rise) / 2; 880 OS.MoveToEx(hdc, drawX, strikeoutY, 0); 881 OS.LineTo(hdc, drawX + run.width, strikeoutY); 882 } 883 OS.SelectObject(hdc, oldPen); 884 if (!hasSelection || fg != selectionForeground.handle) OS.DeleteObject(newPen); 885 } 886 if (partialSelection && fg != selectionForeground.handle) { 887 OS.SetTextColor(hdc, selectionForeground.handle); 888 OS.ScriptTextOut(hdc, run.psc, drawX + offset, drawRunY, OS.ETO_CLIPPED, rect, run.analysis , 0, 0, run.glyphs, run.glyphCount, run.advances, run.justify, run.goffsets); 889 if (run.style != null && (run.style.underline || run.style.strikeout)) { 890 int oldPen = OS.SelectObject(hdc, selPen); 891 if (run.style.underline) { 892 int underlineY = drawY + baseline + 1 - run.style.rise; 893 OS.MoveToEx(hdc, rect.left, underlineY, 0); 894 OS.LineTo(hdc, rect.right, underlineY); 895 } 896 if (run.style.strikeout) { 897 int strikeoutY = drawRunY + run.leading + (run.ascent - run.style.rise) / 2; 898 OS.MoveToEx(hdc, rect.left, strikeoutY, 0); 899 OS.LineTo(hdc, rect.right, strikeoutY); 900 } 901 OS.SelectObject(hdc, oldPen); 902 } 903 } 904 } 905 } 906 } 907 drawX += run.width; 908 } 909 } 910 if (gdip) { 911 if (selBrush != 0) Gdip.SolidBrush_delete(selBrush); 912 if (selBrushFg != 0) Gdip.SolidBrush_delete(selBrushFg); 913 if (selPen != 0) Gdip.Pen_delete(selPen); 914 } else { 915 OS.RestoreDC(hdc, state); 916 if (gdipGraphics != 0) Gdip.Graphics_ReleaseHDC(gdipGraphics, hdc); 917 if (selBrush != 0) OS.DeleteObject (selBrush); 918 if (selPen != 0) OS.DeleteObject (selPen); 919 } 920 } 921 922 void freeRuns () { 923 if (allRuns == null) return; 924 for (int i=0; i<allRuns.length; i++) { 925 StyleItem run = allRuns[i]; 926 run.free(); 927 } 928 allRuns = null; 929 runs = null; 930 segmentsText = null; 931 } 932 933 944 public int getAlignment () { 945 checkLayout(); 946 return alignment; 947 } 948 949 963 public int getAscent () { 964 checkLayout(); 965 return ascent; 966 } 967 968 977 public Rectangle getBounds () { 978 checkLayout(); 979 computeRuns(null); 980 int width = 0; 981 if (wrapWidth != -1) { 982 width = wrapWidth; 983 } else { 984 for (int line=0; line<runs.length; line++) { 985 width = Math.max(width, lineWidth[line] + getLineIndent(line)); 986 } 987 } 988 return new Rectangle (0, 0, width, lineY[lineY.length - 1]); 989 } 990 991 1005public Rectangle getBounds (int start, int end) { 1006 checkLayout(); 1007 computeRuns(null); 1008 int length = text.length(); 1009 if (length == 0) return new Rectangle(0, 0, 0, 0); 1010 if (start > end) return new Rectangle(0, 0, 0, 0); 1011 start = Math.min(Math.max(0, start), length - 1); 1012 end = Math.min(Math.max(0, end), length - 1); 1013 start = translateOffset(start); 1014 end = translateOffset(end); 1015 int left = 0x7fffffff, right = 0; 1016 int top = 0x7fffffff, bottom = 0; 1017 boolean isRTL = (orientation & SWT.RIGHT_TO_LEFT) != 0; 1018 for (int i = 0; i < allRuns.length - 1; i++) { 1019 StyleItem run = allRuns[i]; 1020 int runEnd = run.start + run.length; 1021 if (runEnd <= start) continue; 1022 if (run.start > end) break; 1023 int runLead = run.x; 1024 int runTrail = run.x + run.width; 1025 if (run.start <= start && start < runEnd) { 1026 int cx = 0; 1027 if (run.style != null && run.style.metrics != null) { 1028 GlyphMetrics metrics = run.style.metrics; 1029 cx = metrics.width * (start - run.start); 1030 } else if (!run.tab) { 1031 int[] piX = new int[1]; 1032 int advances = run.justify != 0 ? run.justify : run.advances; 1033 OS.ScriptCPtoX(start - run.start, false, run.length, run.glyphCount, run.clusters, run.visAttrs, advances, run.analysis, piX); 1034 cx = isRTL ? run.width - piX[0] : piX[0]; 1035 } 1036 if (run.analysis.fRTL ^ isRTL) { 1037 runTrail = run.x + cx; 1038 } else { 1039 runLead = run.x + cx; 1040 } 1041 } 1042 if (run.start <= end && end < runEnd) { 1043 int cx = run.width; 1044 if (run.style != null && run.style.metrics != null) { 1045 GlyphMetrics metrics = run.style.metrics; 1046 cx = metrics.width * (end - run.start + 1); 1047 } else if (!run.tab) { 1048 int[] piX = new int[1]; 1049 int advances = run.justify != 0 ? run.justify : run.advances; 1050 OS.ScriptCPtoX(end - run.start, true, run.length, run.glyphCount, run.clusters, run.visAttrs, advances, run.analysis, piX); 1051 cx = isRTL ? run.width - piX[0] : piX[0]; 1052 } 1053 if (run.analysis.fRTL ^ isRTL) { 1054 runLead = run.x + cx; 1055 } else { 1056 runTrail = run.x + cx; 1057 } 1058 } 1059 int lineIndex = 0; 1060 while (lineIndex < runs.length && lineOffset[lineIndex + 1] <= run.start) { 1061 lineIndex++; 1062 } 1063 left = Math.min(left, runLead); 1064 right = Math.max(right, runTrail); 1065 top = Math.min(top, lineY[lineIndex]); 1066 bottom = Math.max(bottom, lineY[lineIndex + 1] - lineSpacing); 1067 } 1068 return new Rectangle(left, top, right - left, bottom - top); 1069} 1070 1071 1085public int getDescent () { 1086 checkLayout(); 1087 return descent; 1088} 1089 1090 1100public Font getFont () { 1101 checkLayout(); 1102 return font; 1103} 1104 1105 1116public int getIndent () { 1117 checkLayout(); 1118 return indent; 1119} 1120 1121 1132public boolean getJustify () { 1133 checkLayout(); 1134 return justify; 1135} 1136 1137int getItemFont (StyleItem item) { 1138 if (item.fallbackFont != 0) return item.fallbackFont; 1139 if (item.style != null && item.style.font != null) { 1140 return item.style.font.handle; 1141 } 1142 if (this.font != null) { 1143 return this.font.handle; 1144 } 1145 return device.systemFont; 1146} 1147 1148 1162public int getLevel (int offset) { 1163 checkLayout(); 1164 computeRuns(null); 1165 int length = text.length(); 1166 if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1167 offset = translateOffset(offset); 1168 for (int i=1; i<allRuns.length; i++) { 1169 if (allRuns[i].start > offset) { 1170 return allRuns[i - 1].analysis.s.uBidiLevel; 1171 } 1172 } 1173 return (orientation & SWT.RIGHT_TO_LEFT) != 0 ? 1 : 0; 1174} 1175 1176 1189public Rectangle getLineBounds(int lineIndex) { 1190 checkLayout(); 1191 computeRuns(null); 1192 if (!(0 <= lineIndex && lineIndex < runs.length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1193 int x = getLineIndent(lineIndex); 1194 int y = lineY[lineIndex]; 1195 int width = lineWidth[lineIndex]; 1196 int height = lineY[lineIndex + 1] - y - lineSpacing; 1197 return new Rectangle (x, y, width, height); 1198} 1199 1200 1210public int getLineCount () { 1211 checkLayout(); 1212 computeRuns(null); 1213 return runs.length; 1214} 1215 1216int getLineIndent (int lineIndex) { 1217 int lineIndent = 0; 1218 if (lineIndex == 0) { 1219 lineIndent = indent; 1220 } else { 1221 StyleItem[] previousLine = runs[lineIndex - 1]; 1222 StyleItem previousRun = previousLine[previousLine.length - 1]; 1223 if (previousRun.lineBreak && !previousRun.softBreak) { 1224 lineIndent = indent; 1225 } 1226 } 1227 if (wrapWidth != -1) { 1228 boolean partialLine = true; 1229 if (justify) { 1230 StyleItem[] lineRun = runs[lineIndex]; 1231 if (lineRun[lineRun.length - 1].softBreak) { 1232 partialLine = false; 1233 } 1234 } 1235 if (partialLine) { 1236 int lineWidth = this.lineWidth[lineIndex] + lineIndent; 1237 switch (alignment) { 1238 case SWT.CENTER: lineIndent += (wrapWidth - lineWidth) / 2; break; 1239 case SWT.RIGHT: lineIndent += wrapWidth - lineWidth; break; 1240 } 1241 } 1242 } 1243 return lineIndent; 1244} 1245 1246 1260public int getLineIndex (int offset) { 1261 checkLayout(); 1262 computeRuns(null); 1263 int length = text.length(); 1264 if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1265 offset = translateOffset(offset); 1266 for (int line=0; line<runs.length; line++) { 1267 if (lineOffset[line + 1] > offset) { 1268 return line; 1269 } 1270 } 1271 return runs.length - 1; 1272} 1273 1274 1287public FontMetrics getLineMetrics (int lineIndex) { 1288 checkLayout(); 1289 computeRuns(null); 1290 if (!(0 <= lineIndex && lineIndex < runs.length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1291 int hDC = device.internal_new_GC(null); 1292 int srcHdc = OS.CreateCompatibleDC(hDC); 1293 TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA(); 1294 OS.SelectObject(srcHdc, font != null ? font.handle : device.systemFont); 1295 OS.GetTextMetrics(srcHdc, lptm); 1296 OS.DeleteDC(srcHdc); 1297 device.internal_dispose_GC(hDC, null); 1298 1299 int ascent = Math.max(lptm.tmAscent, this.ascent); 1300 int descent = Math.max(lptm.tmDescent, this.descent); 1301 int leading = lptm.tmInternalLeading; 1302 if (text.length() != 0) { 1303 StyleItem[] lineRuns = runs[lineIndex]; 1304 for (int i = 0; i<lineRuns.length; i++) { 1305 StyleItem run = lineRuns[i]; 1306 if (run.ascent > ascent) { 1307 ascent = run.ascent; 1308 leading = run.leading; 1309 } 1310 descent = Math.max(descent, run.descent); 1311 } 1312 } 1313 lptm.tmAscent = ascent; 1314 lptm.tmDescent = descent; 1315 lptm.tmHeight = ascent + descent; 1316 lptm.tmInternalLeading = leading; 1317 lptm.tmAveCharWidth = 0; 1318 return FontMetrics.win32_new(lptm); 1319} 1320 1321 1332public int[] getLineOffsets () { 1333 checkLayout(); 1334 computeRuns(null); 1335 int[] offsets = new int[lineOffset.length]; 1336 for (int i = 0; i < offsets.length; i++) { 1337 offsets[i] = untranslateOffset(lineOffset[i]); 1338 } 1339 return offsets; 1340} 1341 1342 1358public Point getLocation (int offset, boolean trailing) { 1359 checkLayout(); 1360 computeRuns(null); 1361 int length = text.length(); 1362 if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1363 length = segmentsText.length(); 1364 offset = translateOffset(offset); 1365 int line; 1366 for (line=0; line<runs.length; line++) { 1367 if (lineOffset[line + 1] > offset) break; 1368 } 1369 line = Math.min(line, runs.length - 1); 1370 StyleItem[] lineRuns = runs[line]; 1371 Point result = null; 1372 if (offset == length) { 1373 result = new Point(lineWidth[line], lineY[line]); 1374 } else { 1375 int width = 0; 1376 for (int i=0; i<lineRuns.length; i++) { 1377 StyleItem run = lineRuns[i]; 1378 int end = run.start + run.length; 1379 if (run.start <= offset && offset < end) { 1380 if (run.style != null && run.style.metrics != null) { 1381 GlyphMetrics metrics = run.style.metrics; 1382 width += metrics.width * (offset - run.start + (trailing ? 1 : 0)); 1383 result = new Point(width, lineY[line]); 1384 } else if (run.tab) { 1385 if (trailing || (offset == length)) width += run.width; 1386 result = new Point(width, lineY[line]); 1387 } else { 1388 int runOffset = offset - run.start; 1389 int cChars = run.length; 1390 int gGlyphs = run.glyphCount; 1391 int[] piX = new int[1]; 1392 int advances = run.justify != 0 ? run.justify : run.advances; 1393 OS.ScriptCPtoX(runOffset, trailing, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX); 1394 if ((orientation & SWT.RIGHT_TO_LEFT) != 0) { 1395 result = new Point(width + (run.width - piX[0]), lineY[line]); 1396 } else { 1397 result = new Point(width + piX[0], lineY[line]); 1398 } 1399 } 1400 break; 1401 } 1402 width += run.width; 1403 } 1404 } 1405 if (result == null) result = new Point(0, 0); 1406 result.x += getLineIndent(line); 1407 return result; 1408} 1409 1410 1429public int getNextOffset (int offset, int movement) { 1430 checkLayout(); 1431 return _getOffset (offset, movement, true); 1432} 1433 1434int _getOffset(int offset, int movement, boolean forward) { 1435 computeRuns(null); 1436 int length = text.length(); 1437 if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1438 if (forward && offset == length) return length; 1439 if (!forward && offset == 0) return 0; 1440 int step = forward ? 1 : -1; 1441 if ((movement & SWT.MOVEMENT_CHAR) != 0) return offset + step; 1442 length = segmentsText.length(); 1443 offset = translateOffset(offset); 1444 SCRIPT_LOGATTR logAttr = new SCRIPT_LOGATTR(); 1445 SCRIPT_PROPERTIES properties = new SCRIPT_PROPERTIES(); 1446 int i = forward ? 0 : allRuns.length - 1; 1447 offset = validadeOffset(offset, step); 1448 do { 1449 StyleItem run = allRuns[i]; 1450 if (run.start <= offset && offset < run.start + run.length) { 1451 if (run.lineBreak && !run.softBreak) return untranslateOffset(run.start); 1452 if (run.tab) return untranslateOffset(run.start); 1453 OS.MoveMemory(properties, device.scripts[run.analysis.eScript], SCRIPT_PROPERTIES.sizeof); 1454 boolean isComplex = properties.fNeedsCaretInfo || properties.fNeedsWordBreaking; 1455 if (isComplex) breakRun(run); 1456 while (run.start <= offset && offset < run.start + run.length) { 1457 if (isComplex) { 1458 OS.MoveMemory(logAttr, run.psla + ((offset - run.start) * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof); 1459 } 1460 switch (movement) { 1461 case SWT.MOVEMENT_CLUSTER: { 1462 if (properties.fNeedsCaretInfo) { 1463 if (!logAttr.fInvalid && logAttr.fCharStop) return untranslateOffset(offset); 1464 } else { 1465 return untranslateOffset(offset); 1466 } 1467 break; 1468 } 1469 case SWT.MOVEMENT_WORD_START: 1470 case SWT.MOVEMENT_WORD: { 1471 if (properties.fNeedsWordBreaking) { 1472 if (!logAttr.fInvalid && logAttr.fWordStop) return untranslateOffset(offset); 1473 } else { 1474 if (offset > 0) { 1475 boolean letterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset)); 1476 boolean previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset - 1)); 1477 if (letterOrDigit != previousLetterOrDigit || !letterOrDigit) { 1478 if (!Compatibility.isWhitespace(segmentsText.charAt(offset))) { 1479 return untranslateOffset(offset); 1480 } 1481 } 1482 } 1483 } 1484 break; 1485 } 1486 case SWT.MOVEMENT_WORD_END: { 1487 if (offset > 0) { 1488 boolean isLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset)); 1489 boolean previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset - 1)); 1490 if (!isLetterOrDigit && previousLetterOrDigit) { 1491 return untranslateOffset(offset); 1492 } 1493 } 1494 break; 1495 } 1496 } 1497 offset = validadeOffset(offset, step); 1498 } 1499 } 1500 i += step; 1501 } while (0 <= i && i < allRuns.length - 1 && 0 <= offset && offset < length); 1502 return forward ? text.length() : 0; 1503} 1504 1505 1528public int getOffset (Point point, int[] trailing) { 1529 checkLayout(); 1530 if (point == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); 1531 return getOffset (point.x, point.y, trailing) ; 1532} 1533 1534 1557public int getOffset (int x, int y, int[] trailing) { 1558 checkLayout(); 1559 computeRuns(null); 1560 if (trailing != null && trailing.length < 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 1561 int line; 1562 int lineCount = runs.length; 1563 for (line=0; line<lineCount; line++) { 1564 if (lineY[line + 1] > y) break; 1565 } 1566 line = Math.min(line, runs.length - 1); 1567 x -= getLineIndent(line); 1568 StyleItem[] lineRuns = runs[line]; 1569 if (x >= lineWidth[line]) x = lineWidth[line] - 1; 1570 if (x < 0) x = 0; 1571 int width = 0; 1572 for (int i = 0; i < lineRuns.length; i++) { 1573 StyleItem run = lineRuns[i]; 1574 if (run.lineBreak && !run.softBreak) return untranslateOffset(run.start); 1575 if (width + run.width > x) { 1576 int xRun = x - width; 1577 if (run.style != null && run.style.metrics != null) { 1578 GlyphMetrics metrics = run.style.metrics; 1579 if (metrics.width > 0) { 1580 if (trailing != null) { 1581 trailing[0] = (xRun % metrics.width < metrics.width / 2) ? 0 : 1; 1582 } 1583 return untranslateOffset(run.start + xRun / metrics.width); 1584 } 1585 } 1586 if (run.tab) { 1587 if (trailing != null) trailing[0] = x < (width + run.width / 2) ? 0 : 1; 1588 return untranslateOffset(run.start); 1589 } 1590 int cChars = run.length; 1591 int cGlyphs = run.glyphCount; 1592 int[] piCP = new int[1]; 1593 int[] piTrailing = new int[1]; 1594 if ((orientation & SWT.RIGHT_TO_LEFT) != 0) { 1595 xRun = run.width - xRun; 1596 } 1597 int advances = run.justify != 0 ? run.justify : run.advances; 1598 OS.ScriptXtoCP(xRun, cChars, cGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piCP, piTrailing); 1599 if (trailing != null) trailing[0] = piTrailing[0]; 1600 return untranslateOffset(run.start + piCP[0]); 1601 } 1602 width += run.width; 1603 } 1604 if (trailing != null) trailing[0] = 0; 1605 return untranslateOffset(lineOffset[line + 1]); 1606} 1607 1608 1617public int getOrientation () { 1618 checkLayout(); 1619 return orientation; 1620} 1621 1622 1641public int getPreviousOffset (int offset, int movement) { 1642 checkLayout(); 1643 return _getOffset (offset, movement, false); 1644} 1645 1646 1660public int[] getRanges () { 1661 checkLayout(); 1662 int[] result = new int[styles.length * 2]; 1663 int count = 0; 1664 for (int i=0; i<styles.length - 1; i++) { 1665 if (styles[i].style != null) { 1666 result[count++] = styles[i].start; 1667 result[count++] = styles[i + 1].start - 1; 1668 } 1669 } 1670 if (count != result.length) { 1671 int[] newResult = new int[count]; 1672 System.arraycopy(result, 0, newResult, 0, count); 1673 result = newResult; 1674 } 1675 return result; 1676} 1677 1678 1687public int[] getSegments () { 1688 checkLayout(); 1689 return segments; 1690} 1691 1692String getSegmentsText() { 1693 if (segments == null) return text; 1694 int nSegments = segments.length; 1695 if (nSegments <= 1) return text; 1696 int length = text.length(); 1697 if (length == 0) return text; 1698 if (nSegments == 2) { 1699 if (segments[0] == 0 && segments[1] == length) return text; 1700 } 1701 char[] oldChars = new char[length]; 1702 text.getChars(0, length, oldChars, 0); 1703 char[] newChars = new char[length + nSegments]; 1704 int charCount = 0, segmentCount = 0; 1705 char separator = orientation == SWT.RIGHT_TO_LEFT ? RTL_MARK : LTR_MARK; 1706 while (charCount < length) { 1707 if (segmentCount < nSegments && charCount == segments[segmentCount]) { 1708 newChars[charCount + segmentCount++] = separator; 1709 } else { 1710 newChars[charCount + segmentCount] = oldChars[charCount++]; 1711 } 1712 } 1713 if (segmentCount < nSegments) { 1714 segments[segmentCount] = charCount; 1715 newChars[charCount + segmentCount++] = separator; 1716 } 1717 return new String (newChars, 0, Math.min(charCount + segmentCount, newChars.length)); 1718} 1719 1720 1729public int getSpacing () { 1730 checkLayout(); 1731 return lineSpacing; 1732} 1733 1734 1747public TextStyle getStyle (int offset) { 1748 checkLayout(); 1749 int length = text.length(); 1750 if (!(0 <= offset && offset < length)) SWT.error(SWT.ERROR_INVALID_RANGE); 1751 for (int i=1; i<styles.length; i++) { 1752 if (styles[i].start > offset) { 1753 return styles[i - 1].style; 1754 } 1755 } 1756 return null; 1757} 1758 1759 1772public TextStyle[] getStyles () { 1773 checkLayout(); 1774 TextStyle[] result = new TextStyle[styles.length]; 1775 int count = 0; 1776 for (int i=0; i<styles.length; i++) { 1777 if (styles[i].style != null) { 1778 result[count++] = styles[i].style; 1779 } 1780 } 1781 if (count != result.length) { 1782 TextStyle[] newResult = new TextStyle[count]; 1783 System.arraycopy(result, 0, newResult, 0, count); 1784 result = newResult; 1785 } 1786 return result; 1787} 1788 1789 1798public int[] getTabs () { 1799 checkLayout(); 1800 return tabs; 1801} 1802 1803 1813public String getText () { 1814 checkLayout(); 1815 return text; 1816} 1817 1818 1827public int getWidth () { 1828 checkLayout(); 1829 return wrapWidth; 1830} 1831 1832 1843public boolean isDisposed () { 1844 return device == null; 1845} 1846 1847 1850StyleItem[] itemize () { 1851 segmentsText = getSegmentsText(); 1852 int length = segmentsText.length(); 1853 SCRIPT_CONTROL scriptControl = new SCRIPT_CONTROL(); 1854 SCRIPT_STATE scriptState = new SCRIPT_STATE(); 1855 final int MAX_ITEM = length + 1; 1856 1857 if ((orientation & SWT.RIGHT_TO_LEFT) != 0) { 1858 scriptState.uBidiLevel = 1; 1859 scriptState.fArabicNumContext = true; 1860 SCRIPT_DIGITSUBSTITUTE psds = new SCRIPT_DIGITSUBSTITUTE(); 1861 OS.ScriptRecordDigitSubstitution(OS.LOCALE_USER_DEFAULT, psds); 1862 OS.ScriptApplyDigitSubstitution(psds, scriptControl, scriptState); 1863 } 1864 1865 int hHeap = OS.GetProcessHeap(); 1866 int pItems = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, MAX_ITEM * SCRIPT_ITEM.sizeof); 1867 if (pItems == 0) SWT.error(SWT.ERROR_NO_HANDLES); 1868 int[] pcItems = new int[1]; 1869 char[] chars = new char[length]; 1870 segmentsText.getChars(0, length, chars, 0); 1871 OS.ScriptItemize(chars, length, MAX_ITEM, scriptControl, scriptState, pItems, pcItems); 1872 1874 StyleItem[] runs = merge(pItems, pcItems[0]); 1875 OS.HeapFree(hHeap, 0, pItems); 1876 return runs; 1877} 1878 1879 1882StyleItem[] merge (int items, int itemCount) { 1883 int count = 0, start = 0, end = segmentsText.length(), itemIndex = 0, styleIndex = 0; 1884 StyleItem[] runs = new StyleItem[itemCount + styles.length]; 1885 SCRIPT_ITEM scriptItem = new SCRIPT_ITEM(); 1886 boolean linkBefore = false; 1887 while (start < end) { 1888 StyleItem item = new StyleItem(); 1889 item.start = start; 1890 item.style = styles[styleIndex].style; 1891 runs[count++] = item; 1892 OS.MoveMemory(scriptItem, items + itemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof); 1893 item.analysis = scriptItem.a; 1894 if (linkBefore) { 1895 item.analysis.fLinkBefore = true; 1896 linkBefore = false; 1897 } 1898 scriptItem.a = new SCRIPT_ANALYSIS(); 1899 OS.MoveMemory(scriptItem, items + (itemIndex + 1) * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof); 1900 int itemLimit = scriptItem.iCharPos; 1901 int styleLimit = translateOffset(styles[styleIndex + 1].start); 1902 if (styleLimit <= itemLimit) { 1903 styleIndex++; 1904 start = styleLimit; 1905 if (start < itemLimit && 0 < start && start < end) { 1906 char pChar = segmentsText.charAt(start - 1); 1907 char tChar = segmentsText.charAt(start); 1908 if (!Compatibility.isWhitespace(pChar) && !Compatibility.isWhitespace(tChar)) { 1909 item.analysis.fLinkAfter = true; 1910 linkBefore = true; 1911 } 1912 } 1913 } 1914 if (itemLimit <= styleLimit) { 1915 itemIndex++; 1916 start = itemLimit; 1917 } 1918 item.length = start - item.start; 1919 } 1920 StyleItem item = new StyleItem(); 1921 item.start = end; 1922 OS.MoveMemory(scriptItem, items + itemCount * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof); 1923 item.analysis = scriptItem.a; 1924 runs[count++] = item; 1925 if (runs.length != count) { 1926 StyleItem[] result = new StyleItem[count]; 1927 System.arraycopy(runs, 0, result, 0, count); 1928 return result; 1929 } 1930 return runs; 1931} 1932 1933 1936StyleItem[] reorder (StyleItem[] runs, boolean terminate) { 1937 int length = runs.length; 1938 if (length <= 1) return runs; 1939 byte[] bidiLevels = new byte[length]; 1940 for (int i=0; i<length; i++) { 1941 bidiLevels[i] = (byte)(runs[i].analysis.s.uBidiLevel & 0x1F); 1942 } 1943 1949 StyleItem lastRun = runs[length - 1]; 1950 if (lastRun.lineBreak && !lastRun.softBreak) { 1951 bidiLevels[length - 1] = 0; 1952 } 1953 int[] log2vis = new int[length]; 1954 OS.ScriptLayout(length, bidiLevels, null, log2vis); 1955 StyleItem[] result = new StyleItem[length]; 1956 for (int i=0; i<length; i++) { 1957 result[log2vis[i]] = runs[i]; 1958 } 1959 if ((orientation & SWT.RIGHT_TO_LEFT) != 0) { 1960 if (terminate) length--; 1961 for (int i = 0; i < length / 2 ; i++) { 1962 StyleItem tmp = result[i]; 1963 result[i] = result[length - i - 1]; 1964 result[length - i - 1] = tmp; 1965 } 1966 } 1967 return result; 1968} 1969 1970 1988public void setAlignment (int alignment) { 1989 checkLayout(); 1990 int mask = SWT.LEFT | SWT.CENTER | SWT.RIGHT; 1991 alignment &= mask; 1992 if (alignment == 0) return; 1993 if ((alignment & SWT.LEFT) != 0) alignment = SWT.LEFT; 1994 if ((alignment & SWT.RIGHT) != 0) alignment = SWT.RIGHT; 1995 if (this.alignment == alignment) return; 1996 freeRuns(); 1997 this.alignment = alignment; 1998} 1999 2000 2018public void setAscent(int ascent) { 2019 checkLayout(); 2020 if (ascent < -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 2021 if (this.ascent == ascent) return; 2022 freeRuns(); 2023 this.ascent = ascent; 2024} 2025 2026 2044public void setDescent(int descent) { 2045 checkLayout(); 2046 if (descent < -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 2047 if (this.descent == descent) return; 2048 freeRuns(); 2049 this.descent = descent; 2050} 2051 2052 2068public void setFont (Font font) { 2069 checkLayout(); 2070 if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 2071 if (this.font == font) return; 2072 if (font != null && font.equals(this.font)) return; 2073 freeRuns(); 2074 this.font = font; 2075} 2076 2077 2089public void setIndent (int indent) { 2090 checkLayout(); 2091 if (indent < 0) return; 2092 if (this.indent == indent) return; 2093 freeRuns(); 2094 this.indent = indent; 2095} 2096 2097 2109public void setJustify (boolean justify) { 2110 checkLayout(); 2111 if (this.justify == justify) return; 2112 freeRuns(); 2113 this.justify = justify; 2114} 2115 2116 2126public void setOrientation (int orientation) { 2127 checkLayout(); 2128 int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT; 2129 orientation &= mask; 2130 if (orientation == 0) return; 2131 if ((orientation & SWT.LEFT_TO_RIGHT) != 0) orientation = SWT.LEFT_TO_RIGHT; 2132 if (this.orientation == orientation) return; 2133 this.orientation = orientation; 2134 freeRuns(); 2135} 2136 2137 2155public void setSegments(int[] segments) { 2156 checkLayout(); 2157 if (this.segments == null && segments == null) return; 2158 if (this.segments != null && segments != null) { 2159 if (this.segments.length == segments.length) { 2160 int i; 2161 for (i = 0; i <segments.length; i++) { 2162 if (this.segments[i] != segments[i]) break; 2163 } 2164 if (i == segments.length) return; 2165 } 2166 } 2167 freeRuns(); 2168 this.segments = segments; 2169} 2170 2171 2184public void setSpacing (int spacing) { 2185 checkLayout(); 2186 if (spacing < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 2187 if (this.lineSpacing == spacing) return; 2188 freeRuns(); 2189 this.lineSpacing = spacing; 2190} 2191 2192 2205public void setStyle (TextStyle style, int start, int end) { 2206 checkLayout(); 2207 int length = text.length(); 2208 if (length == 0) return; 2209 if (start > end) return; 2210 start = Math.min(Math.max(0, start), length - 1); 2211 end = Math.min(Math.max(0, end), length - 1); 2212 int low = -1; 2213 int high = styles.length; 2214 while (high - low > 1) { 2215 int index = (high + low) / 2; 2216 if (styles[index + 1].start > start) { 2217 high = index; 2218 } else { 2219 low = index; 2220 } 2221 } 2222 if (0 <= high && high < styles.length) { 2223 StyleItem item = styles[high]; 2224 if (item.start == start && styles[high + 1].start - 1 == end) { 2225 if (style == null) { 2226 if (item.style == null) return; 2227 } else { 2228 if (style.equals(item.style)) return; 2229 } 2230 } 2231 } 2232 freeRuns(); 2233 int modifyStart = high; 2234 int modifyEnd = modifyStart; 2235 while (modifyEnd < styles.length) { 2236 if (styles[modifyEnd + 1].start > end) break; 2237 modifyEnd++; 2238 } 2239 if (modifyStart == modifyEnd) { 2240 int styleStart = styles[modifyStart].start; 2241 int styleEnd = styles[modifyEnd + 1].start - 1; 2242 if (styleStart == start && styleEnd == end) { 2243 styles[modifyStart].style = style; 2244 return; 2245 } 2246 if (styleStart != start && styleEnd != end) { 2247 StyleItem[] newStyles = new StyleItem[styles.length + 2]; 2248 System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); 2249 StyleItem item = new StyleItem(); 2250 item.start = start; 2251 item.style = style; 2252 newStyles[modifyStart + 1] = item; 2253 item = new StyleItem(); 2254 item.start = end + 1; 2255 item.style = styles[modifyStart].style; 2256 newStyles[modifyStart + 2] = item; 2257 System.arraycopy(styles, modifyEnd + 1, newStyles, modifyEnd + 3, styles.length - modifyEnd - 1); 2258 styles = newStyles; 2259 return; 2260 } 2261 } 2262 if (start == styles[modifyStart].start) modifyStart--; 2263 if (end == styles[modifyEnd + 1].start - 1) modifyEnd++; 2264 int newLength = styles.length + 1 - (modifyEnd - modifyStart - 1); 2265 StyleItem[] newStyles = new StyleItem[newLength]; 2266 System.arraycopy(styles, 0, newStyles, 0, modifyStart + 1); 2267 StyleItem item = new StyleItem(); 2268 item.start = start; 2269 item.style = style; 2270 newStyles[modifyStart + 1] = item; 2271 styles[modifyEnd].start = end + 1; 2272 System.arraycopy(styles, modifyEnd, newStyles, modifyStart + 2, styles.length - modifyEnd); 2273 styles = newStyles; 2274} 2275 2276 2287public void setTabs (int[] tabs) { 2288 checkLayout(); 2289 if (this.tabs == null && tabs == null) return; 2290 if (this.tabs != null && tabs !=null) { 2291 if (this.tabs.length == tabs.length) { 2292 int i; 2293 for (i = 0; i <tabs.length; i++) { 2294 if (this.tabs[i] != tabs[i]) break; 2295 } 2296 if (i == tabs.length) return; 2297 } 2298 } 2299 freeRuns(); 2300 this.tabs = tabs; 2301} 2302 2303 2315public void setText (String text) { 2316 checkLayout(); 2317 if (text == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); 2318 if (text.equals(this.text)) return; 2319 freeRuns(); 2320 this.text = text; 2321 styles = new StyleItem[2]; 2322 styles[0] = new StyleItem(); 2323 styles[1] = new StyleItem(); 2324 styles[1].start = text.length(); 2325} 2326 2327 2343public void setWidth (int width) { 2344 checkLayout(); 2345 if (width < -1 || width == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); 2346 if (this.wrapWidth == width) return; 2347 freeRuns(); 2348 this.wrapWidth = width; 2349} 2350 2351boolean shape (int hdc, StyleItem run, char[] chars, int[] glyphCount, int maxGlyphs) { 2352 int hr = OS.ScriptShape(hdc, run.psc, chars, chars.length, maxGlyphs, run.analysis, run.glyphs, run.clusters, run.visAttrs, glyphCount); 2353 run.glyphCount = glyphCount[0]; 2354 if (hr != OS.USP_E_SCRIPT_NOT_IN_FONT) { 2355 SCRIPT_FONTPROPERTIES fp = new SCRIPT_FONTPROPERTIES (); 2356 fp.cBytes = SCRIPT_FONTPROPERTIES.sizeof; 2357 OS.ScriptGetFontProperties(hdc, run.psc, fp); 2358 short[] glyphs = new short[glyphCount[0]]; 2359 OS.MoveMemory(glyphs, run.glyphs, glyphs.length * 2); 2360 int i; 2361 for (i = 0; i < glyphs.length; i++) { 2362 if (glyphs[i] == fp.wgDefault) break; 2363 } 2364 if (i == glyphs.length) return true; 2365 } 2366 if (run.psc != 0) { 2367 OS.ScriptFreeCache(run.psc); 2368 glyphCount[0] = 0; 2369 OS.MoveMemory(run.psc, glyphCount, 4); 2370 } 2371 run.glyphCount = 0; 2372 return false; 2373} 2374 2375 2378void shape (final int hdc, final StyleItem run) { 2379 int[] buffer = new int[1]; 2380 char[] chars = new char[run.length]; 2381 segmentsText.getChars(run.start, run.start + run.length, chars, 0); 2382 int maxGlyphs = (chars.length * 3 / 2) + 16; 2383 int hHeap = OS.GetProcessHeap(); 2384 run.glyphs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2); 2385 if (run.glyphs == 0) SWT.error(SWT.ERROR_NO_HANDLES); 2386 run.clusters = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2); 2387 if (run.clusters == 0) SWT.error(SWT.ERROR_NO_HANDLES); 2388 run.visAttrs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * SCRIPT_VISATTR_SIZEOF); 2389 if (run.visAttrs == 0) SWT.error(SWT.ERROR_NO_HANDLES); 2390 run.psc = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, 4); 2391 if (run.psc == 0) SWT.error(SWT.ERROR_NO_HANDLES); 2392 if (!shape(hdc, run, chars, buffer, maxGlyphs)) { 2393 if (mLangFontLink2 != 0) { 2394 int[] dwCodePages = new int[1]; 2395 int[] cchCodePages = new int[1]; 2396 2397 OS.VtblCall(4, mLangFontLink2, chars, chars.length, 0, dwCodePages, cchCodePages); 2398 int[] hNewFont = new int[1]; 2399 2400 if (OS.VtblCall(10, mLangFontLink2, hdc, dwCodePages[0], chars[0], hNewFont) == OS.S_OK) { 2401 int hFont = OS.SelectObject(hdc, hNewFont[0]); 2402 if (shape(hdc, run, chars, buffer, maxGlyphs)) { 2403 run.fallbackFont = hNewFont[0]; 2404 } else { 2405 2406 OS.VtblCall(8, mLangFontLink2, hNewFont[0]); 2407 OS.SelectObject(hdc, hFont); 2408 SCRIPT_PROPERTIES properties = new SCRIPT_PROPERTIES(); 2409 OS.MoveMemory(properties, device.scripts[run.analysis.eScript], SCRIPT_PROPERTIES.sizeof); 2410 if (properties.fPrivateUseArea) { 2411 run.analysis.fNoGlyphIndex = true; 2412 } 2413 OS.ScriptShape(hdc, run.psc, chars, chars.length, maxGlyphs, run.analysis, run.glyphs, run.clusters, run.visAttrs, buffer); 2414 run.glyphCount = buffer[0]; 2415 } 2416 } 2417 } 2418 } 2419 int[] abc = new int[3]; 2420 run.advances = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, run.glyphCount * 4); 2421 if (run.advances == 0) SWT.error(SWT.ERROR_NO_HANDLES); 2422 run.goffsets = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, run.glyphCount * GOFFSET_SIZEOF); 2423 if (run.goffsets == 0) SWT.error(SWT.ERROR_NO_HANDLES); 2424 OS.ScriptPlace(hdc, run.psc, run.glyphs, run.glyphCount, run.visAttrs, run.analysis, run.advances, run.goffsets, abc); 2425 if (run.style != null && run.style.metrics != null) { 2426 GlyphMetrics metrics = run.style.metrics; 2427 2432 run.width = metrics.width * Math.max (1, run.glyphCount); 2433 run.ascent = metrics.ascent; 2434 run.descent = metrics.descent; 2435 run.leading = 0; 2436 } else { 2437 run.width = abc[0] + abc[1] + abc[2]; 2438 TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA(); 2439 OS.GetTextMetrics(hdc, lptm); 2440 run.ascent = lptm.tmAscent; 2441 run.descent = lptm.tmDescent; 2442 run.leading = lptm.tmInternalLeading; 2443 } 2444 if (run.style != null) { 2445 run.ascent += run.style.rise; 2446 run.descent -= +run.style.rise; 2447 } 2448} 2449 2450int validadeOffset(int offset, int step) { 2451 offset += step; 2452 if (segments != null && segments.length > 2) { 2453 for (int i = 0; i < segments.length; i++) { 2454 if (translateOffset(segments[i]) - 1 == offset) { 2455 offset += step; 2456 break; 2457 } 2458 } 2459 } 2460 return offset; 2461} 2462 2463 2469public String toString () { 2470 if (isDisposed()) return "TextLayout {*DISPOSED*}"; 2471 return "TextLayout {}"; 2472} 2473 2474int translateOffset(int offset) { 2475 if (segments == null) return offset; 2476 int nSegments = segments.length; 2477 if (nSegments <= 1) return offset; 2478 int length = text.length(); 2479 if (length == 0) return offset; 2480 if (nSegments == 2) { 2481 if (segments[0] == 0 && segments[1] == length) return offset; 2482 } 2483 for (int i = 0; i < nSegments && offset - i >= segments[i]; i++) { 2484 offset++; 2485 } 2486 return offset; 2487} 2488 2489int untranslateOffset(int offset) { 2490 if (segments == null) return offset; 2491 int nSegments = segments.length; 2492 if (nSegments <= 1) return offset; 2493 int length = text.length(); 2494 if (length == 0) return offset; 2495 if (nSegments == 2) { 2496 if (segments[0] == 0 && segments[1] == length) return offset; 2497 } 2498 for (int i = 0; i < nSegments && offset > segments[i]; i++) { 2499 offset--; 2500 } 2501 return offset; 2502} 2503} 2504 | Popular Tags |