]
Eric Williams reassigned ERT-762:
---------------------------------
Sprint: devex #173 Oct 2019
Assignee: Eric Williams
[GTK] Performance of TextLayout.getBounds() is very bad for long text
[EBZ#551588]
----------------------------------------------------------------------------------
Key: ERT-762
URL:
https://issues.jboss.org/browse/ERT-762
Project: Eclipse Release Train
Issue Type: Task
Components: Platform
Reporter: Friendly Jira Robot
Assignee: Eric Williams
Priority: Major
Labels: 4.14_M1, SWT, bzira
I've noticed a slow performance of TextLayout.getBounds() method on Linux. The
profiler shows an excessive amount of calls to OS.pango_layout_get_line_count(layout)
method. Looking through the code I'm noticing that this is due to the bad design in
TextLayout class, as it repeats calls to same OS methods repeatedly in a loop.
The TextLayout.getBounds() method looks like this:
public Rectangle getBounds() {
checkLayout();
Rectangle bounds = DPIUtil.autoScaleDown(getDevice(), getBoundsInPixels());
int lineCount = OS.pango_layout_get_line_count(layout);
int totalLineheight = getScaledVerticalIndent();
for (int i = 0; i < lineCount; i++) {
totalLineheight += this.getLineBounds(i).height +
OS.PANGO_PIXELS(OS.pango_layout_get_spacing(layout));
}
bounds.height = totalLineheight;
return bounds;
}
Here I believe the result of OS.pango_layout_get_spacing(layout) could be cached. Further
down the line this calls TextLayout.getLineBoundsInPixels method.
Rectangle getLineBoundsInPixels(int lineIndex) {
computeRuns();
int lineCount = OS.pango_layout_get_line_count(layout);
if (!(0 <= lineIndex && lineIndex < lineCount))
SWT.error(SWT.ERROR_INVALID_RANGE);
long iter = OS.pango_layout_get_iter(layout);
if (iter == 0) SWT.error(SWT.ERROR_NO_HANDLES);
for (int i = 0; i < lineIndex; i++) OS.pango_layout_iter_next_line(iter);
PangoRectangle rect = new PangoRectangle();
OS.pango_layout_iter_get_line_extents(iter, null, rect);
OS.pango_layout_iter_free(iter);
int x = OS.PANGO_PIXELS(rect.x);
int y = OS.PANGO_PIXELS(rect.y);
int width = OS.PANGO_PIXELS(rect.width);
int height = OS.PANGO_PIXELS(rect.height);
if (ascentInPoints != -1 && descentInPoints != -1) {
height = Math.max (height, DPIUtil.autoScaleUp(getDevice(), ascentInPoints +
descentInPoints));
}
x += Math.min (indent, wrapIndent);
return new Rectangle(x, y, width, height);
}
This method repeats the call to OS.pango_layout_get_line_count. Also things like
computeRuns() and OS.pango_layout_get_iter(layout) could be done once per
TextLayout.getBounds call. Done in a loop this quickly escalates to slow performance.
I believe TextLayout.getBounds() should be refactored to minimize repeated calls and
reuse results.