8270265: LineBreakMeasurer calculates incorrect line breaks with zero-width characters

Reviewed-by: achung, prr
This commit is contained in:
Daniel Gredler 2025-03-13 20:27:27 +00:00 committed by Phil Race
parent 3da5e3fe10
commit 7fc776e2ac
6 changed files with 22 additions and 10 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -493,10 +493,9 @@ class ExtendedTextSourceLabel extends ExtendedTextLabel implements Decoration.La
--start;
while (width >= -epsilon && ++start < length) {
int cidx = l2v(start) * numvals + advx;
if (cidx >= charinfo.length) {
break; // layout bailed for some reason
}
float adv = charinfo[cidx];
float adv = cidx < charinfo.length ?
charinfo[cidx] : // layout provided info for this glyph
0; // glyph info omitted, assume no advance
if (adv != 0) {
width -= adv + advTracking;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -272,6 +272,7 @@ JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape
buffer = hb_buffer_create();
hb_buffer_set_script(buffer, getHBScriptCode(script));
hb_buffer_set_invisible_glyph(buffer, INVISIBLE_GLYPH_ID);
hb_buffer_set_language(buffer,
hb_ot_tag_to_language(HB_OT_TAG_DEFAULT_LANGUAGE));
if ((flags & TYPO_RTL) != 0) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -107,6 +107,7 @@ JDKEXPORT void jdk_hb_shape(
buffer = hb_buffer_create();
hb_buffer_set_script(buffer, getHBScriptCode(script));
hb_buffer_set_invisible_glyph(buffer, INVISIBLE_GLYPH_ID);
hb_buffer_set_language(buffer,
hb_ot_tag_to_language(HB_OT_TAG_DEFAULT_LANGUAGE));
if ((flags & TYPO_RTL) != 0) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -48,6 +48,8 @@
extern "C" {
#endif
// Matches sun.font.CharToGlyphMapper.INVISIBLE_GLYPH_ID
#define INVISIBLE_GLYPH_ID 0xffff
hb_font_t* jdk_font_create_hbp(
hb_face_t* face,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -50,6 +50,9 @@ typedef struct JDKFontInfo_Struct {
#define HBFloatToFixedScale ((float)(1 << 16))
#define HBFloatToFixed(f) ((unsigned int)((f) * HBFloatToFixedScale))
// Matches sun.font.CharToGlyphMapper.INVISIBLE_GLYPH_ID
#define INVISIBLE_GLYPH_ID 0xffff
/*
* Note:
*

View File

@ -23,7 +23,7 @@
/**
* @test
* @bug 8208377 6562489
* @bug 8208377 6562489 8270265
* @summary Confirm that format-category glyphs are not rendered or measured.
*/
@ -275,6 +275,12 @@ public class FormatCharAdvanceTest {
g2d.drawString(as2.getIterator(), w / 2, h / 2);
ab2 = findTextBoundingBox(image).width;
assertEqual(ab1, ab2, "drawString (using AttributedCharacterIterator)", c, font);
int max = metrics.stringWidth("AB") + 2; // add a little wiggle room to the max width
LineBreakMeasurer measurer1 = new LineBreakMeasurer(as1.getIterator(), frc);
LineBreakMeasurer measurer2 = new LineBreakMeasurer(as2.getIterator(), frc);
assertEqual(2, measurer1.nextOffset(max), "nextOffset 1", c, font);
assertEqual(7, measurer2.nextOffset(max), "nextOffset 2", c, font);
}
private static void assertEqual(int i1, int i2, String scenario, char c, Font font) {