1 11 package org.eclipse.swt.internal; 12 13 14 import java.util.Hashtable ; 15 16 import org.eclipse.swt.SWT; 17 import org.eclipse.swt.graphics.GC; 18 import org.eclipse.swt.internal.win32.*; 19 22 public class BidiUtil { 23 24 public static final int KEYBOARD_NON_BIDI = 0; 26 public static final int KEYBOARD_BIDI = 1; 27 28 static int isBidiPlatform = -1; 30 31 public static final int CLASSIN = 1; 33 public static final int LINKBEFORE = 2; 34 public static final int LINKAFTER = 4; 35 36 static Hashtable languageMap = new Hashtable (); 39 static Hashtable keyMap = new Hashtable (); 40 static Hashtable oldProcMap = new Hashtable (); 41 47 static final String CLASS_NAME = "org.eclipse.swt.internal.BidiUtil"; static Callback callback; 50 static { 51 try { 52 callback = new Callback (Class.forName (CLASS_NAME), "windowProc", 4); if (callback.getAddress () == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS); 54 } catch (ClassNotFoundException e) {} 55 } 56 57 static final int GCP_REORDER = 0x0002; 59 static final int GCP_GLYPHSHAPE = 0x0010; 60 static final int GCP_LIGATE = 0x0020; 61 static final int GCP_CLASSIN = 0x00080000; 62 static final byte GCPCLASS_ARABIC = 2; 63 static final byte GCPCLASS_HEBREW = 2; 64 static final byte GCPCLASS_LOCALNUMBER = 4; 65 static final byte GCPCLASS_LATINNUMBER = 5; 66 static final int GCPGLYPH_LINKBEFORE = 0x8000; 67 static final int GCPGLYPH_LINKAFTER = 0x4000; 68 static final int ETO_CLIPPED = 0x4; 70 static final int ETO_GLYPH_INDEX = 0x0010; 71 static final int LANG_ARABIC = 0x01; 73 static final int LANG_HEBREW = 0x0d; 74 static final String CD_PG_HEBREW = "1255"; static final String CD_PG_ARABIC = "1256"; static final int HKL_NEXT = 1; 79 static final int HKL_PREV = 0; 80 81 87 public static final int CLASS_HEBREW = GCPCLASS_ARABIC; 88 public static final int CLASS_ARABIC = GCPCLASS_HEBREW; 89 public static final int CLASS_LOCALNUMBER = GCPCLASS_LOCALNUMBER; 90 public static final int CLASS_LATINNUMBER = GCPCLASS_LATINNUMBER; 91 public static final int REORDER = GCP_REORDER; 92 public static final int LIGATE = GCP_LIGATE; 93 public static final int GLYPHSHAPE = GCP_GLYPHSHAPE; 94 95 107 public static void addLanguageListener (int hwnd, Runnable runnable) { 108 languageMap.put(new Integer (hwnd), runnable); 109 subclass(hwnd); 110 } 111 114 static int EnumSystemLanguageGroupsProc(int lpLangGrpId, int lpLangGrpIdString, int lpLangGrpName, int options, int lParam) { 115 if (lpLangGrpId == OS.LGRPID_HEBREW) { 116 isBidiPlatform = 1; 117 return 0; 118 } 119 if (lpLangGrpId == OS.LGRPID_ARABIC) { 120 isBidiPlatform = 1; 121 return 0; 122 } 123 return 1; 124 } 125 135 public static void drawGlyphs(GC gc, char[] renderBuffer, int[] renderDx, int x, int y) { 136 int length = renderDx.length; 137 138 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { 139 if (OS.GetLayout (gc.handle) != 0) { 140 reverse(renderDx); 141 renderDx[length-1]--; reverse(renderBuffer); 143 } 144 } 145 int oldBkMode = OS.SetBkMode(gc.handle, OS.TRANSPARENT); 147 OS.ExtTextOutW(gc.handle, x, y, ETO_GLYPH_INDEX , null, renderBuffer, renderBuffer.length, renderDx); 148 OS.SetBkMode(gc.handle, oldBkMode); 149 } 150 168 public static char[] getRenderInfo(GC gc, String text, int[] order, byte[] classBuffer, int[] dx, int flags, int [] offsets) { 169 int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle); 170 int hHeap = OS.GetProcessHeap(); 171 int[] lpCs = new int[8]; 172 int cs = OS.GetTextCharset(gc.handle); 173 boolean isRightOriented = false; 174 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { 175 isRightOriented = OS.GetLayout(gc.handle) != 0; 176 } 177 OS.TranslateCharsetInfo(cs, lpCs, OS.TCI_SRCCHARSET); 178 TCHAR textBuffer = new TCHAR(lpCs[1], text, false); 179 int byteCount = textBuffer.length(); 180 boolean linkBefore = (flags & LINKBEFORE) == LINKBEFORE; 181 boolean linkAfter = (flags & LINKAFTER) == LINKAFTER; 182 183 GCP_RESULTS result = new GCP_RESULTS(); 184 result.lStructSize = GCP_RESULTS.sizeof; 185 result.nGlyphs = byteCount; 186 int lpOrder = result.lpOrder = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4); 187 int lpDx = result.lpDx = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4); 188 int lpClass = result.lpClass = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); 189 int lpGlyphs = result.lpGlyphs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 2); 190 191 int dwFlags = 0; 193 int glyphFlags = 0; 194 dwFlags |= GCP_REORDER; 197 if ((fontLanguageInfo & GCP_LIGATE) == GCP_LIGATE) { 198 dwFlags |= GCP_LIGATE; 199 glyphFlags |= 0; 200 } 201 if ((fontLanguageInfo & GCP_GLYPHSHAPE) == GCP_GLYPHSHAPE) { 202 dwFlags |= GCP_GLYPHSHAPE; 203 if (linkBefore) { 204 glyphFlags |= GCPGLYPH_LINKBEFORE; 205 } 206 if (linkAfter) { 207 glyphFlags |= GCPGLYPH_LINKAFTER; 208 } 209 } 210 byte[] lpGlyphs2; 211 if (linkBefore || linkAfter) { 212 lpGlyphs2 = new byte[2]; 213 lpGlyphs2[0]=(byte)glyphFlags; 214 lpGlyphs2[1]=(byte)(glyphFlags >> 8); 215 } 216 else { 217 lpGlyphs2 = new byte[] {(byte) glyphFlags}; 218 } 219 OS.MoveMemory(result.lpGlyphs, lpGlyphs2, lpGlyphs2.length); 220 221 if ((flags & CLASSIN) == CLASSIN) { 222 dwFlags |= GCP_CLASSIN; 224 OS.MoveMemory(result.lpClass, classBuffer, classBuffer.length); 225 } 226 227 char[] glyphBuffer = new char[result.nGlyphs]; 228 int glyphCount = 0; 229 for (int i=0; i<offsets.length-1; i++) { 230 int offset = offsets [i]; 231 int length = offsets [i+1] - offsets [i]; 232 233 result.nGlyphs = length; 236 TCHAR textBuffer2 = new TCHAR(lpCs[1], text.substring(offset, offset + length), false); 237 OS.GetCharacterPlacement(gc.handle, textBuffer2, textBuffer2.length(), 0, result, dwFlags); 238 239 if (dx != null) { 240 int [] dx2 = new int [result.nGlyphs]; 241 OS.MoveMemory(dx2, result.lpDx, dx2.length * 4); 242 if (isRightOriented) { 243 reverse(dx2); 244 } 245 System.arraycopy (dx2, 0, dx, glyphCount, dx2.length); 246 } 247 if (order != null) { 248 int [] order2 = new int [length]; 249 OS.MoveMemory(order2, result.lpOrder, order2.length * 4); 250 translateOrder(order2, glyphCount, isRightOriented); 251 System.arraycopy (order2, 0, order, offset, length); 252 } 253 if (classBuffer != null) { 254 byte [] classBuffer2 = new byte [length]; 255 OS.MoveMemory(classBuffer2, result.lpClass, classBuffer2.length); 256 System.arraycopy (classBuffer2, 0, classBuffer, offset, length); 257 } 258 char[] glyphBuffer2 = new char[result.nGlyphs]; 259 OS.MoveMemory(glyphBuffer2, result.lpGlyphs, glyphBuffer2.length * 2); 260 if (isRightOriented) { 261 reverse(glyphBuffer2); 262 } 263 System.arraycopy (glyphBuffer2, 0, glyphBuffer, glyphCount, glyphBuffer2.length); 264 glyphCount += glyphBuffer2.length; 265 266 result.lpOrder += length * 4; 272 result.lpDx += length * 4; 273 result.lpClass += length; 274 result.lpGlyphs += glyphBuffer2.length * 2; 275 } 276 277 278 OS.HeapFree(hHeap, 0, lpGlyphs); 279 OS.HeapFree(hHeap, 0, lpClass); 280 OS.HeapFree(hHeap, 0, lpDx); 281 OS.HeapFree(hHeap, 0, lpOrder); 282 return glyphBuffer; 283 } 284 301 public static void getOrderInfo(GC gc, String text, int[] order, byte[] classBuffer, int flags, int [] offsets) { 302 int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle); 303 int hHeap = OS.GetProcessHeap(); 304 int[] lpCs = new int[8]; 305 int cs = OS.GetTextCharset(gc.handle); 306 OS.TranslateCharsetInfo(cs, lpCs, OS.TCI_SRCCHARSET); 307 TCHAR textBuffer = new TCHAR(lpCs[1], text, false); 308 int byteCount = textBuffer.length(); 309 boolean isRightOriented = false; 310 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { 311 isRightOriented = OS.GetLayout(gc.handle) != 0; 312 } 313 314 GCP_RESULTS result = new GCP_RESULTS(); 315 result.lStructSize = GCP_RESULTS.sizeof; 316 result.nGlyphs = byteCount; 317 int lpOrder = result.lpOrder = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4); 318 int lpClass = result.lpClass = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); 319 320 int dwFlags = 0; 323 dwFlags |= GCP_REORDER; 326 if ((fontLanguageInfo & GCP_LIGATE) == GCP_LIGATE) { 327 dwFlags |= GCP_LIGATE; 328 } 329 if ((fontLanguageInfo & GCP_GLYPHSHAPE) == GCP_GLYPHSHAPE) { 330 dwFlags |= GCP_GLYPHSHAPE; 331 } 332 if ((flags & CLASSIN) == CLASSIN) { 333 dwFlags |= GCP_CLASSIN; 336 OS.MoveMemory(result.lpClass, classBuffer, classBuffer.length); 337 } 338 339 int glyphCount = 0; 340 for (int i=0; i<offsets.length-1; i++) { 341 int offset = offsets [i]; 342 int length = offsets [i+1] - offsets [i]; 343 result.nGlyphs = length; 346 TCHAR textBuffer2 = new TCHAR(lpCs[1], text.substring(offset, offset + length), false); 347 OS.GetCharacterPlacement(gc.handle, textBuffer2, textBuffer2.length(), 0, result, dwFlags); 348 349 if (order != null) { 350 int [] order2 = new int [length]; 351 OS.MoveMemory(order2, result.lpOrder, order2.length * 4); 352 translateOrder(order2, glyphCount, isRightOriented); 353 System.arraycopy (order2, 0, order, offset, length); 354 } 355 if (classBuffer != null) { 356 byte [] classBuffer2 = new byte [length]; 357 OS.MoveMemory(classBuffer2, result.lpClass, classBuffer2.length); 358 System.arraycopy (classBuffer2, 0, classBuffer, offset, length); 359 } 360 glyphCount += result.nGlyphs; 361 362 result.lpOrder += length * 4; 368 result.lpClass += length; 369 } 370 371 372 OS.HeapFree(hHeap, 0, lpClass); 373 OS.HeapFree(hHeap, 0, lpOrder); 374 } 375 383 public static int getFontBidiAttributes(GC gc) { 384 int fontStyle = 0; 385 int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle); 386 if (((fontLanguageInfo & GCP_REORDER) != 0)) { 387 fontStyle |= REORDER; 388 } 389 if (((fontLanguageInfo & GCP_LIGATE) != 0)) { 390 fontStyle |= LIGATE; 391 } 392 if (((fontLanguageInfo & GCP_GLYPHSHAPE) != 0)) { 393 fontStyle |= GLYPHSHAPE; 394 } 395 return fontStyle; 396 } 397 404 public static int getKeyboardLanguage() { 405 int layout = OS.GetKeyboardLayout(0); 406 layout = layout & 0x000000FF; 409 if (layout == LANG_HEBREW) return KEYBOARD_BIDI; 410 if (layout == LANG_ARABIC) return KEYBOARD_BIDI; 411 return KEYBOARD_NON_BIDI; 413 } 414 420 static int[] getKeyboardLanguageList() { 421 int maxSize = 10; 422 int[] tempList = new int[maxSize]; 423 int size = OS.GetKeyboardLayoutList(maxSize, tempList); 424 int[] list = new int[size]; 425 System.arraycopy(tempList, 0, list, 0, size); 426 return list; 427 } 428 436 public static boolean isBidiPlatform() { 437 if (OS.IsWinCE) return false; 438 if (isBidiPlatform != -1) return isBidiPlatform == 1; 440 isBidiPlatform = 0; 441 442 if (!isKeyboardBidi()) return false; 451 452 Callback callback = null; 453 try { 454 callback = new Callback (Class.forName (CLASS_NAME), "EnumSystemLanguageGroupsProc", 5); int lpEnumSystemLanguageGroupsProc = callback.getAddress (); 456 if (lpEnumSystemLanguageGroupsProc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); 457 OS.EnumSystemLanguageGroups(lpEnumSystemLanguageGroupsProc, OS.LGRPID_INSTALLED, 0); 458 callback.dispose (); 459 } catch (ClassNotFoundException e) { 460 if (callback != null) callback.dispose(); 461 } 462 if (isBidiPlatform == 1) return true; 463 String codePage = String.valueOf(OS.GetACP()); 466 if (CD_PG_ARABIC.equals(codePage) || CD_PG_HEBREW.equals(codePage)) { 467 isBidiPlatform = 1; 468 } 469 return isBidiPlatform == 1; 470 } 471 478 public static boolean isKeyboardBidi() { 479 int[] list = getKeyboardLanguageList(); 480 for (int i=0; i<list.length; i++) { 481 int id = list[i] & 0x000000FF; 482 if ((id == LANG_ARABIC) || (id == LANG_HEBREW)) { 483 return true; 484 } 485 } 486 return false; 487 } 488 494 public static void removeLanguageListener (int hwnd) { 495 languageMap.remove(new Integer (hwnd)); 496 unsubclass(hwnd); 497 } 498 507 public static void setKeyboardLanguage(int language) { 508 if (language == getKeyboardLanguage()) return; 510 511 if (language == KEYBOARD_BIDI) { 512 int[] list = getKeyboardLanguageList(); 514 for (int i=0; i<list.length; i++) { 516 int id = list[i] & 0x000000FF; 517 if ((id == LANG_ARABIC) || (id == LANG_HEBREW)) { 518 OS.ActivateKeyboardLayout(list[i], 0); 519 return; 520 } 521 } 522 } else { 523 int[] list = getKeyboardLanguageList(); 525 for (int i=0; i<list.length; i++) { 528 int id = list[i] & 0x000000FF; 529 if ((id != LANG_HEBREW) && (id != LANG_ARABIC)) { 530 OS.ActivateKeyboardLayout(list[i], 0); 531 return; 532 } 533 } 534 } 535 } 536 546 public static boolean setOrientation (int hwnd, int orientation) { 547 if (OS.IsWinCE) return false; 548 if (OS.WIN32_VERSION < OS.VERSION(4, 10)) return false; 549 int bits = OS.GetWindowLong (hwnd, OS.GWL_EXSTYLE); 550 if ((orientation & SWT.RIGHT_TO_LEFT) != 0) { 551 bits |= OS.WS_EX_LAYOUTRTL; 552 } else { 553 bits &= ~OS.WS_EX_LAYOUTRTL; 554 } 555 OS.SetWindowLong (hwnd, OS.GWL_EXSTYLE, bits); 556 return true; 557 } 558 563 static void subclass(int hwnd) { 564 Integer key = new Integer (hwnd); 565 if (oldProcMap.get(key) == null) { 566 int oldProc = OS.GetWindowLong(hwnd, OS.GWL_WNDPROC); 567 oldProcMap.put(key, new Integer (oldProc)); 568 OS.SetWindowLong(hwnd, OS.GWL_WNDPROC, callback.getAddress()); 569 } 570 } 571 576 static void reverse(char[] charArray) { 577 int length = charArray.length; 578 for (int i = 0; i <= (length - 1) / 2; i++) { 579 char tmp = charArray[i]; 580 charArray[i] = charArray[length - 1 - i]; 581 charArray[length - 1 - i] = tmp; 582 } 583 } 584 589 static void reverse(int[] intArray) { 590 int length = intArray.length; 591 for (int i = 0; i <= (length - 1) / 2; i++) { 592 int tmp = intArray[i]; 593 intArray[i] = intArray[length - 1 - i]; 594 intArray[length - 1 - i] = tmp; 595 } 596 } 597 605 static void translateOrder(int[] orderArray, int glyphCount, boolean isRightOriented) { 606 int maxOrder = 0; 607 int length = orderArray.length; 608 if (isRightOriented) { 609 for (int i=0; i<length; i++) { 610 maxOrder = Math.max(maxOrder, orderArray[i]); 611 } 612 } 613 for (int i=0; i<length; i++) { 614 if (isRightOriented) orderArray[i] = maxOrder - orderArray[i]; 615 orderArray [i] += glyphCount; 616 } 617 } 618 623 static void unsubclass(int hwnd) { 624 Integer key = new Integer (hwnd); 625 if (languageMap.get(key) == null && keyMap.get(key) == null) { 626 Integer proc = (Integer ) oldProcMap.remove(key); 627 if (proc == null) return; 628 OS.SetWindowLong(hwnd, OS.GWL_WNDPROC, proc.intValue()); 629 } 630 } 631 640 static int windowProc (int hwnd, int msg, int wParam, int lParam) { 641 Integer key = new Integer (hwnd); 642 switch (msg) { 643 case 0x51 : 644 Runnable runnable = (Runnable ) languageMap.get (key); 645 if (runnable != null) runnable.run (); 646 break; 647 } 648 Integer oldProc = (Integer )oldProcMap.get(key); 649 return OS.CallWindowProc (oldProc.intValue(), hwnd, msg, wParam, lParam); 650 } 651 652 } 653 | Popular Tags |