Community
Participate
Working Groups
Build Identifier: Version: 3.7.0 Build id: I20110613-1736 Run this code in Workbench UI thread: TextLayout layout = new TextLayout(Display.getDefault()); String text = ""; String word = "abcde"; int l = word.length(); for (int n = 1; n < 30; n++) { text += "\t" + word; layout.setText(text); long t = System.currentTimeMillis(); layout.getPreviousOffset(text.length(), SWT.MOVEMENT_CLUSTER); long dt = System.currentTimeMillis() - t; System.out.println("Time spent (ms): " + dt + ", constant = " + dt * 1d / (l * n * n)); } On my computer, I got constant=0.056 so that T=0.056*L*N^2 (ms), where T is the time for executing getPreviousOffset(int,int), L is the average length of word, N is the number of words in the text. At L=5 and N=100, time is about 3 seconds. Next, consider CTabFolderRenderer.shortenText(GC, String, int, String), which has this code: while (end > 0) { text = text.substring(0, end); int l = gc.textExtent(text, FLAGS).x; if (l + ellipseWidth <= width) { break; } end = layout.getPreviousOffset(end, SWT.MOVEMENT_CLUSTER); } In all cases that I observed, getPreviousOffset(end, SWT.MOVEMENT_CLUSTER) returned end-1, so that time consumed by this cycle is T=0.10*L^2*N^3 (for L=5, N=100 that makes 42 minutes), here constant is 0.10 instead of 0.05 because GC.textExtent(String,int) has the same poor performance. Of course, usually name for tab folder is selected reasonably short and without \t symbols, but assume an application that dynamically generates tab folder name from some arbitrary user data and relies on SWT rendering will efficiently shorten too long names. I think that whatever performance of TextLayout and GC may be, search in CTabFolderRenderer.shortenText for a maximal substring that fits into the provided space should be bisectional rather than cutting off one symbol at a time. Reproducible: Always
Consider CLabel.shortenText(GC, String, int). This method does implement the bisectional search for a maximal substring that fits into the provided space, and T ~ L*N^2 * log(L*N). For L=5, N=100 I got 2 minutes, which is much better than performance of CTabFolderRenderer.shortenText(GC, String, int, String). However, CLabel.shortenText(GC, String, int) is called through paint listener, so that Eclipse will hang 2 minutes after each paint event, which is sent on many occasions. Besides, it is more probable that a text with '\t' characters will be set to CLabel, e.g. a programmer has to read an internationalized constant from a resource bundle and may not modify it, or he wants to use the fact that character '\t' is rendered by CLabel into a wider space between words than a whitespace.
Finally, I have considered one more case, StyledText.getWordPrevious(int, int, boolean), where this performance would really be fatal. But in this method the call TextLayout.getPreviousOffset works quite fast, and why? It turns out that TextLayout instance prepared by StyledTextRenderer.getTextLayout has field int[] tabs set. That makes all the difference. Add line layout.setTabs(new int[]{12}); to my code in description above, and its performance will improve 1000 times. Consequently, 1. There is a way to make TextLayout.getPreviousOffset(int,int) run fast. Please consider if it is a bug or a feature for it to have poor performance when property 'tabs' is not set. 2. Methods CTabFolderRenderer.shortenText(GC, String, int, String) CLabel.shortenText(GC, String, int) should set property 'tabs' on TextLayout instance.
Is there an SWT snippet that goes with this ticket?
No interest from reporter. Please reopen when you are ready to provide pure swt snippet to ease work on the bug.