diff --git a/src/core/pal/feature.cpp b/src/core/pal/feature.cpp index 266adf1cff3c..f8918c4134b1 100644 --- a/src/core/pal/feature.cpp +++ b/src/core/pal/feature.cpp @@ -1059,6 +1059,10 @@ LabelPosition* FeaturePart::curvedPlacementAtOffset( PointSet* path_positions, d // grab the next character according to the orientation LabelInfo::CharacterInfo& ci = ( orientation > 0 ? li->char_info[i] : li->char_info[li->char_num-i-1] ); + if ( qgsDoubleNear( ci.width, 0.0 ) ) + // Certain scripts rely on zero-width character, skip those to prevent failure (see #15801) + continue; + double start_x, start_y, end_x, end_y; if ( nextCharPosition( ci.width, path_distances[index], path_positions, index, distance, start_x, start_y, end_x, end_y ) == false ) { diff --git a/tests/src/python/test_qgspallabeling_placement.py b/tests/src/python/test_qgspallabeling_placement.py index 571d2b75501b..14368ba41d72 100644 --- a/tests/src/python/test_qgspallabeling_placement.py +++ b/tests/src/python/test_qgspallabeling_placement.py @@ -433,6 +433,18 @@ def test_label_line_avoid_jaggy(self): self.removeMapLayer(self.layer) self.layer = None + def test_label_curved_zero_width_char(self): + # Test that curved label work with zero-width characters + self.layer = TestQgsPalLabeling.loadFeatureLayer('line') + self._TestMapSettings = self.cloneMapSettings(self._MapSettings) + self.lyr.placement = QgsPalLayerSettings.Curved + self.lyr.placementFlags = QgsPalLayerSettings.OnLine + self.lyr.fieldName = "'invisible​space'" + self.lyr.isExpression = True + self.checkTest() + self.removeMapLayer(self.layer) + self.layer = None + if __name__ == '__main__': # NOTE: unless PAL_SUITE env var is set all test class methods will be run # SEE: test_qgspallabeling_tests.suiteTests() to define suite diff --git a/tests/src/python/test_qgspallabeling_tests.py b/tests/src/python/test_qgspallabeling_tests.py index bdad4cbdae09..f121c752e94e 100644 --- a/tests/src/python/test_qgspallabeling_tests.py +++ b/tests/src/python/test_qgspallabeling_tests.py @@ -308,8 +308,9 @@ def test_curved_placement_below(self): self.lyr.placementFlags = QgsPalLayerSettings.BelowLine | QgsPalLayerSettings.MapOrientation self.checkTest() - # noinspection PyPep8Naming + + def suiteTests(): """ Use to define which tests are run when PAL_SUITE is set. diff --git a/tests/testdata/control_images/expected_pal_placement/sp_label_curved_zero_width_char/sp_label_curved_zero_width_char.png b/tests/testdata/control_images/expected_pal_placement/sp_label_curved_zero_width_char/sp_label_curved_zero_width_char.png new file mode 100644 index 000000000000..555b8a814e1a Binary files /dev/null and b/tests/testdata/control_images/expected_pal_placement/sp_label_curved_zero_width_char/sp_label_curved_zero_width_char.png differ