Skip to content

Conversation

deepika-u
Copy link
Contributor

Corrected TextLayout to produce right number of lines when '\r\n' sequence comes.

Fixes #184

@sravanlakkimsetti
@niraj-modi
@merks
Can one of you review this fix please.

@deepika-u deepika-u requested a review from niraj-modi as a code owner July 3, 2024 13:01
@deepika-u
Copy link
Contributor Author

Anyone testing this pr can use the below snippet.
simple test case is with text1.
complex test case is with text2.

package org.eclipse.swt.bugs4;

/*
 * TextLayout example snippet: text with underline and strike through
 *
 * For a list of all SWT example snippets see
 * http://www.eclipse.org/swt/snippets/
 *
 * @since 3.1
 */
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;

public class Issue184 {

	private static FontData[] getFontData(Font font, int style) {
		FontData[] fontDatas = font.getFontData();
		for (FontData fontData : fontDatas) {
			fontData.setStyle(style);
		}
		return fontDatas;
	}

	public static void main(String[] args) {
		Display display = new Display();
		final Shell shell = new Shell(display, SWT.SHELL_TRIM | SWT.DOUBLE_BUFFERED);
		shell.setText("Underline, Strike Out");
		//String text = "Here is 1.\r\n\r\nsome text that is 2.\r\nunderlined or 3.\rstruck out or 4.\nboth.";
		String text1 = "0123456789\r\n\r\n0123456789\r\n0123456789\r0123456789\n0123456789";
		String text2 = "\r\n0123456789\r\n\r\n01\r\n456789\r\n0123456789\r0123456789\n0123456789";

		FontData[] fontData = getFontData(shell.getFont(), SWT.BOLD);
		Font font = new Font(shell.getDisplay(), fontData);

		FontData[] fontData1 = getFontData(shell.getFont(), SWT.ITALIC | SWT.BOLD);
		Font font1 = new Font(shell.getDisplay(), fontData1);

		FontData[] fontData2 = getFontData(shell.getFont(), SWT.BOLD);
		Font font2 = new Font(shell.getDisplay(), fontData2);

		final TextLayout layout = new TextLayout(display);
		//layout.setText(text1);
		layout.setText(text2);

		TextStyle style1 = new TextStyle(font, null, null);
		//layout.setStyle(style1, 0, 16);
		layout.setStyle(style1, 5, 16);

		TextStyle style2 = new TextStyle(font1, null, null);
		layout.setStyle(style2, 21, 24);

		TextStyle style3 = new TextStyle(font2, null, null);
		layout.setStyle(style3, 27, 31);
		//layout.setStyle(style3, 25, 29);

		int[] offsets = layout.getLineOffsets();
		System.out.println(offsets.length);
		shell.addListener(SWT.Paint, event -> {
			Point point = new Point(10, 10);
			int width = shell.getClientArea().width - 2 * point.x;
			layout.setWidth(width);
			layout.draw(event.gc, point.x, point.y);
		});
		shell.setSize(400, 300);
		shell.open();
		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}
		layout.dispose();
		display.dispose();
	}
}

Copy link
Contributor

github-actions bot commented Jul 3, 2024

Test Results

   486 files  ±0     486 suites  ±0   9m 49s ⏱️ +25s
 4 307 tests +1   4 294 ✅ +1   13 💤 ±0  0 ❌ ±0 
16 412 runs  +4  16 304 ✅ +4  108 💤 ±0  0 ❌ ±0 

Results for commit 55dc1f3. ± Comparison against base commit 8845e70.

♻️ This comment has been updated with latest results.

}
char ch = segmentsText.charAt(start);
if(ch == '\r') {
ch = segmentsText.charAt(start+1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is a boundcheck required here maybe? Just assume a single \r at end of line would read bejond the end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes agree

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am checking on further if the string in full is just a "\r", what needs to be done.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you agree to my changes, i can squash the commits.

@deepika-u deepika-u force-pushed the fix_for_issue184 branch 2 times, most recently from 89bd04a to aae8e16 Compare July 9, 2024 04:48
@deepika-u
Copy link
Contributor Author

@niraj-modi @merks
Can you also please review this?

@laeubi : Do you have any additional comments on this fix? or are we good to merge this?

Copy link
Contributor

@merks merks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have time for a more detailed for the next days. But some comments generally follow a for or if keyword with a space.

String text, segmentsText;
int lineSpacingInPoints;
String text, segmentsText, originalText;
int lineSpacingInPoints, previousCountNextLine = 0, previousEnd = -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initializing to 0 is pointless and actually generates more byte code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated initialization as part of constructor.

case '\t':
item.tab = true;
break;
if(ch == '\r' && (start+1 < end)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting of if( is poor. The () around the < condition is redundant and odd that it's not used for the == test

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

corrected it.

loop = previousEnd+1;
else
loop = previousEnd;
for(int i = loop; i < end; i++) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here for( is not nice format.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

corrected it.

@deepika-u deepika-u force-pushed the fix_for_issue184 branch 3 times, most recently from 0740eef to 26a2d76 Compare July 15, 2024 07:57
this.originalText = text;
String[] strings = text.split("\r");
text = "";
for(int i = 0; i < strings.length; i++)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formatting of this for loop could also be improved.

@deepika-u deepika-u force-pushed the fix_for_issue184 branch 2 times, most recently from e60de1d to 223b000 Compare July 16, 2024 06:15
this.originalText = text;
String[] strings = text.split("\r");
text = "";
for (int i = 0; i < strings.length; i++)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be done using a map reduction. Anyway, please add braces to the for loop

reference

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's this a complicated and poorly performance way of doing test.replace("\r", "")?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@merks yes, looks like it. Your approach is the best to me!

Copy link
Contributor Author

@deepika-u deepika-u Jul 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me test and update here back.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @merks for your feedback, after updating this i found a better way of fixing the issue. So new change is updated, you may please review now.

else
loop = previousEnd;
for (int i = loop; i < end; i++) {
if (originalText.charAt(i) == '\r' && originalText.charAt(i+1) =='\n')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is i + 1 necessarily < end?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me check it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are correct, when string ends with \r, it is resulting OOB exception. So corrected it.

@deepika-u deepika-u force-pushed the fix_for_issue184 branch 2 times, most recently from 79bb600 to 52e92e2 Compare August 6, 2024 06:44
@deepika-u
Copy link
Contributor Author

@niraj-modi
Can you also please review this? so that it can be merged before M3.

@merks @laeubi @Wittmaxi : Do you have any additional comments on this fix? or are we good to merge this?

@deepika-u deepika-u force-pushed the fix_for_issue184 branch 3 times, most recently from 2e2b765 to 4d7e7e8 Compare August 9, 2024 06:18
@deepika-u
Copy link
Contributor Author

@merks @laeubi @Wittmaxi
Can one of you review the changes please.

@merks
Copy link
Contributor

merks commented Aug 9, 2024

@deepika-u

Could you please squash this to a single commit?

@deepika-u
Copy link
Contributor Author

deepika-u commented Aug 12, 2024

@deepika-u

Could you please squash this to a single commit?

Done.

@deepika-u
Copy link
Contributor Author

@merks
We have crossed the M2 milestone for 4.34 and entered into M3 already. Can you find some time to check on this please so that atleast for this release, its available for customers.

Copy link
Contributor

@merks merks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks okay to me.

That being said, I would prefer that at least one other person deeply involved in SWT reviews this too.

@merks
Copy link
Contributor

merks commented Oct 21, 2024

@HeikoKlare

Do you know who else might be good to review this?

@deepika-u
Copy link
Contributor Author

@sratz @jukzi @laeubi @HeikoKlare
Can one of you review this please.
@merks thanks alot for your time.
But he feels if anyone else also reviews it would be great. - Thanks alot in advance, hoping this would go in 4.34.

Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not worked on TextLayout so far. Thus, unfortunately, I cannot say with high confidence whether the overall change is okay. Still, from what I understand, the conceptual change and the code for it looks sound to me. I've tested the proposed change with the snippet in the original issue and it indeed fixes it.

I have remarks regarding the automated and manual test. In particular the automated test does not seem to be an adequate regression test, as the same test succeeds on master, thus it does not seem to cover the addressed issue.

assertNull(layout.getStyle(5));
layout.dispose();

layout = new TextLayout (display);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test with these changes succeeds on master, so it's not a regression test for the changes made in this PR. Can you adapt the test so that it serves as a regression test for the addressed issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we have not changed the behavior of the api's. The original behavior of the api's still work the same. We are internally detecting, correcting and passing the corrected content in specific cases only. We dint even add new api's. It is only the look and feel by which you can make out if some extra lines are expected or not expected varies. - is my understanding.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I mistakenly expected the added test to be a regression test for the fix because of #1320 (comment)

Still, this change is no refactoring but affects the behavior of public APIs (e.g., TextLayout#draw(...) behaves differently). I guess that, e.g., also TextLayout#getBounds() now behaves differently, so wouldn't it be possible to have a regression test comparing the bounds of two configurations that should actually result in the bounds but did not do before this change (or vice versa)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HeikoKlare
As per your suggestion i have added new junit tests with TextLayout#getLineCount() and TextLayout#getBounds().
Since this change is only with respect to windows, i have excluded mac, gtk for the tests to run.

I guess this makes it all complete as we discussed. If i missed out any, please do let me know.

Can you review it and take it forward please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please hold on, let me cross check and update you again.

Copy link
Contributor Author

@deepika-u deepika-u Dec 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @HeikoKlare
Sorry for the confusion caused.
I am successfull in adding only TextLayout#getLineCount() junit. I think we can go ahead with this pr now.

I have tried even TextLayout#getBounds() but had to withdraw as the behavior is not consistent across.
With the sample input taken,

  • On master, getBounds() is returning {0, 0, 30, 220} where width and height are 30, 220 respectively. [junit is failing]
  • On the branch where i committed my changes(fix_for_issue184), getBounds() is returning {0, 0, 43, 140}. [junit is passing]
  • To cross check, i have pulled the pr 1320 to local, getBounds() is returning {0, 0, 43, 140}. [junit is passing]
  • But on the build machine, getBounds() is returning {0, 0, 34, 105}. [junit is failing because it is getting 34 but expecting 43]. -> https://github.com/eclipse-platform/eclipse.platform.swt/actions/runs/12312890737/job/34365830603?pr=1320
    Neither able to understand the reason for the failure(to fix) nor able to replicate the problem locally to debug further.

Can you please check now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HeikoKlare : Need your time to take this forward please?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HeikoKlare : Need your inputs here please?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for adding the regression test. That one, testing getLineCount(), makes even more sense to me for testing the fix than testing the changed result of getBounds(). 👍

The PR is ready to go from my side.
Just a small final remark regarding the added test: I am just wondering whether it may not be even better to use different expected line count values for the different platforms in the test instead of excluding the test for GTK and Cocoa. Since the functionality is not broken or non-existent on those other platform but just produces expected different results, testing for those other results seems to be more comprehensible to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HeikoKlare
Thanks for your time. I have updated them now, can you take a look now. Assuming everything is done, can you take this forward please.

@HeikoKlare
Copy link
Contributor

And one additional remark: since the TextLayout is very essential and we do not seem to have completely confident reviews so far, I am not sure whether we should bring this kind of change in M3. Maybe it makes more sense to bring in the next M1 to have better implicit testing until it is finally released? The issue has been there for quite a long time without higher complains that I am not sure whether the gain outweighs the risk of regression.

@deepika-u deepika-u force-pushed the fix_for_issue184 branch 2 times, most recently from c368f7f to 514957c Compare October 25, 2024 11:43
@deepika-u
Copy link
Contributor Author

deepika-u commented Oct 25, 2024

And one additional remark: since the TextLayout is very essential and we do not seem to have completely confident reviews so far, I am not sure whether we should bring this kind of change in M3. Maybe it makes more sense to bring in the next M1 to have better implicit testing until it is finally released? The issue has been there for quite a long time without higher complains that I am not sure whether the gain outweighs the risk of regression.

Thanks for your opinion. Since it is already tested now by various people, i feel we are safe to merge this. Considering the M3 deadline is 8th Nov(2 weeks far and not away like 2days or so) and we can give it a try. If something is breaking we'll revert it immediately and rectify to make it to next M1? Atleast this risk we can take to improve SWT - i feel so in particularly such long standing issues when they passed all the stages of fixing, review, successfully verified.
This is a windows specific change and not on common code in particluar.

@deepika-u deepika-u force-pushed the fix_for_issue184 branch 9 times, most recently from a3510b6 to 7f93fcd Compare December 19, 2024 09:17
@deepika-u deepika-u force-pushed the fix_for_issue184 branch 4 times, most recently from 8a34eda to af452c1 Compare January 2, 2025 12:56
sequence comes. Added some junit tests as well. Updated getStyle() and
setStyle() accordingly. Added failing and success junits again.

Fixes eclipse-platform#184
@HeikoKlare
Copy link
Contributor

This looks good now and we also have Ed's approval, thus merging.

@HeikoKlare HeikoKlare merged commit 6104592 into eclipse-platform:master Jan 2, 2025
14 checks passed
@deepika-u
Copy link
Contributor Author

Verified this issue on below build.
Eclipse SDK
Version: 2025-03 (4.35)
Build id: I20250107-1800
OS: Windows 11, v.10.0, x86_64 / win32
Java vendor: Eclipse Adoptium
Java runtime version: 23.0.1+11
Java version: 23.0.1

Number of lines: 7

@jukzi
Copy link
Contributor

jukzi commented Jan 10, 2025

This PR introduced a regression #1714, please fix.
org.eclipse.swt.graphics.TextLayout.getRanges() tries to return only ranges with style!= null. TextLayoutgetStyle(range) for such a range should always return not null.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TextLayout Produces Wrong Lines for '\r\n'

9 participants