diff --git a/src/symbol/shaping.js b/src/symbol/shaping.js index 71269981578..5e8e48ce881 100644 --- a/src/symbol/shaping.js +++ b/src/symbol/shaping.js @@ -154,7 +154,8 @@ function shapeText(text: Formatted, spacing: number, translate: [number, number], writingMode: 1 | 2, - allowVerticalPlacement: boolean): Shaping | false { + allowVerticalPlacement: boolean, + symbolPlacement: string): Shaping | false { const logicalInput = TaggedString.fromFeature(text, defaultFontStack); if (writingMode === WritingMode.vertical) { @@ -169,7 +170,7 @@ function shapeText(text: Formatted, lines = []; const untaggedLines = processBidirectionalText(logicalInput.toString(), - determineLineBreaks(logicalInput, spacing, maxWidth, glyphs)); + determineLineBreaks(logicalInput, spacing, maxWidth, glyphs, symbolPlacement)); for (const line of untaggedLines) { const taggedLine = new TaggedString(); taggedLine.text = line; @@ -186,7 +187,7 @@ function shapeText(text: Formatted, const processedLines = processStyledBidirectionalText(logicalInput.text, logicalInput.sectionIndex, - determineLineBreaks(logicalInput, spacing, maxWidth, glyphs)); + determineLineBreaks(logicalInput, spacing, maxWidth, glyphs, symbolPlacement)); for (const line of processedLines) { const taggedLine = new TaggedString(); taggedLine.text = line[0]; @@ -195,7 +196,7 @@ function shapeText(text: Formatted, lines.push(taggedLine); } } else { - lines = breakLines(logicalInput, determineLineBreaks(logicalInput, spacing, maxWidth, glyphs)); + lines = breakLines(logicalInput, determineLineBreaks(logicalInput, spacing, maxWidth, glyphs, symbolPlacement)); } const positionedGlyphs = []; @@ -358,8 +359,9 @@ function leastBadBreaks(lastLineBreak: ?Break): Array { function determineLineBreaks(logicalInput: TaggedString, spacing: number, maxWidth: number, - glyphMap: {[string]: {[number]: ?StyleGlyph}}): Array { - if (!maxWidth) + glyphMap: {[string]: {[number]: ?StyleGlyph}}, + symbolPlacement: string): Array { + if (symbolPlacement !== 'point') return []; if (!logicalInput) diff --git a/src/symbol/symbol_layout.js b/src/symbol/symbol_layout.js index b85310ef051..eb27ff076a1 100644 --- a/src/symbol/symbol_layout.js +++ b/src/symbol/symbol_layout.js @@ -183,7 +183,8 @@ export function performSymbolLayout(bucket: SymbolBucket, "center" : layout.get('text-justify').evaluate(feature, {}); - const maxWidth = layout.get('symbol-placement') === 'point' ? + const symbolPlacement = layout.get('symbol-placement'); + const maxWidth = symbolPlacement === 'point' ? layout.get('text-max-width').evaluate(feature, {}) * ONE_EM : 0; @@ -193,7 +194,7 @@ export function performSymbolLayout(bucket: SymbolBucket, // writing mode, thus, default left justification is used. If Latin // scripts would need to be supported, this should take into account other justifications. shapedTextOrientations.vertical = shapeText(text, glyphMap, fontstack, maxWidth, lineHeight, textAnchor, - 'left', spacingIfAllowed, textOffset, WritingMode.vertical, true); + 'left', spacingIfAllowed, textOffset, WritingMode.vertical, true, symbolPlacement); } }; @@ -215,7 +216,7 @@ export function performSymbolLayout(bucket: SymbolBucket, // If using text-variable-anchor for the layer, we use a center anchor for all shapings and apply // the offsets for the anchor in the placement step. const shaping = shapeText(text, glyphMap, fontstack, maxWidth, lineHeight, 'center', - justification, spacingIfAllowed, textOffset, WritingMode.horizontal, false); + justification, spacingIfAllowed, textOffset, WritingMode.horizontal, false, symbolPlacement); if (shaping) { shapedTextOrientations.horizontal[justification] = shaping; singleLine = shaping.lineCount === 1; @@ -231,7 +232,7 @@ export function performSymbolLayout(bucket: SymbolBucket, // Horizontal point or line label. const shaping = shapeText(text, glyphMap, fontstack, maxWidth, lineHeight, textAnchor, textJustify, spacingIfAllowed, - textOffset, WritingMode.horizontal, false); + textOffset, WritingMode.horizontal, false, symbolPlacement); if (shaping) shapedTextOrientations.horizontal[textJustify] = shaping; // Vertical point label (if allowVerticalPlacement is enabled). @@ -240,7 +241,7 @@ export function performSymbolLayout(bucket: SymbolBucket, // Verticalized line label. if (allowsVerticalWritingMode(unformattedText) && textAlongLine && keepUpright) { shapedTextOrientations.vertical = shapeText(text, glyphMap, fontstack, maxWidth, lineHeight, textAnchor, textJustify, - spacingIfAllowed, textOffset, WritingMode.vertical, false); + spacingIfAllowed, textOffset, WritingMode.vertical, false, symbolPlacement); } } diff --git a/test/integration/render-tests/symbol-placement/line-center-buffer/style.json b/test/integration/render-tests/symbol-placement/line-center-buffer/style.json index d873e86d1f4..4f517d88b86 100644 --- a/test/integration/render-tests/symbol-placement/line-center-buffer/style.json +++ b/test/integration/render-tests/symbol-placement/line-center-buffer/style.json @@ -45,7 +45,8 @@ "text-font": [ "Open Sans Semibold", "Arial Unicode MS Bold" - ] + ], + "text-max-width": 0 } }, { diff --git a/test/integration/render-tests/text-max-width/unlimited/expected.png b/test/integration/render-tests/text-max-width/unlimited/expected.png deleted file mode 100644 index 8b525273c51..00000000000 Binary files a/test/integration/render-tests/text-max-width/unlimited/expected.png and /dev/null differ diff --git a/test/integration/render-tests/text-max-width/zero-width-point-placement/expected.png b/test/integration/render-tests/text-max-width/zero-width-point-placement/expected.png new file mode 100644 index 00000000000..953f78a2dbc Binary files /dev/null and b/test/integration/render-tests/text-max-width/zero-width-point-placement/expected.png differ diff --git a/test/integration/render-tests/text-max-width/unlimited/style.json b/test/integration/render-tests/text-max-width/zero-width-point-placement/style.json similarity index 100% rename from test/integration/render-tests/text-max-width/unlimited/style.json rename to test/integration/render-tests/text-max-width/zero-width-point-placement/style.json diff --git a/test/unit/symbol/shaping.test.js b/test/unit/symbol/shaping.test.js index ad2ae98407b..e3367fea6bc 100644 --- a/test/unit/symbol/shaping.test.js +++ b/test/unit/symbol/shaping.test.js @@ -21,37 +21,37 @@ test('shaping', (t) => { JSON.parse('{}'); - shaped = shaping.shapeText(Formatted.fromString(`hi${String.fromCharCode(0)}`), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString(`hi${String.fromCharCode(0)}`), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal, false, 'point'); if (UPDATE) fs.writeFileSync(path.join(__dirname, '/../../expected/text-shaping-null.json'), JSON.stringify(shaped, null, 2)); t.deepEqual(shaped, JSON.parse(fs.readFileSync(path.join(__dirname, '/../../expected/text-shaping-null.json')))); // Default shaping. - shaped = shaping.shapeText(Formatted.fromString('abcde'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString('abcde'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal, false, 'point'); if (UPDATE) fs.writeFileSync(path.join(__dirname, '/../../expected/text-shaping-default.json'), JSON.stringify(shaped, null, 2)); t.deepEqual(shaped, JSON.parse(fs.readFileSync(path.join(__dirname, '/../../expected/text-shaping-default.json')))); // Letter spacing. - shaped = shaping.shapeText(Formatted.fromString('abcde'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0.125 * oneEm, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString('abcde'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0.125 * oneEm, [0, 0], WritingMode.horizontal, false, 'point'); if (UPDATE) fs.writeFileSync(path.join(__dirname, '/../../expected/text-shaping-spacing.json'), JSON.stringify(shaped, null, 2)); t.deepEqual(shaped, JSON.parse(fs.readFileSync(path.join(__dirname, '/../../expected/text-shaping-spacing.json')))); // Line break. - shaped = shaping.shapeText(Formatted.fromString('abcde abcde'), glyphs, fontStack, 4 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString('abcde abcde'), glyphs, fontStack, 4 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal, false, 'point'); if (UPDATE) fs.writeFileSync(path.join(__dirname, '/../../expected/text-shaping-linebreak.json'), JSON.stringify(shaped, null, 2)); t.deepEqual(shaped, require('../../expected/text-shaping-linebreak.json')); const expectedNewLine = JSON.parse(fs.readFileSync(path.join(__dirname, '/../../expected/text-shaping-newline.json'))); - shaped = shaping.shapeText(Formatted.fromString('abcde\nabcde'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString('abcde\nabcde'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0, [0, 0], WritingMode.horizontal, false, 'point'); if (UPDATE) fs.writeFileSync(path.join(__dirname, '/../../expected/text-shaping-newline.json'), JSON.stringify(shaped, null, 2)); t.deepEqual(shaped, expectedNewLine); - shaped = shaping.shapeText(Formatted.fromString('abcde\r\nabcde'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString('abcde\r\nabcde'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0, [0, 0], WritingMode.horizontal, false, 'point'); t.deepEqual(shaped.positionedGlyphs, expectedNewLine.positionedGlyphs); const expectedNewLinesInMiddle = JSON.parse(fs.readFileSync(path.join(__dirname, '/../../expected/text-shaping-newlines-in-middle.json'))); - shaped = shaping.shapeText(Formatted.fromString('abcde\n\nabcde'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString('abcde\n\nabcde'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0, [0, 0], WritingMode.horizontal, false, 'point'); if (UPDATE) fs.writeFileSync(path.join(__dirname, '/../../expected/text-shaping-newlines-in-middle.json'), JSON.stringify(shaped, null, 2)); t.deepEqual(shaped, expectedNewLinesInMiddle); @@ -59,20 +59,20 @@ test('shaping', (t) => { // a position is ideal for breaking. const expectedZeroWidthSpaceBreak = JSON.parse(fs.readFileSync(path.join(__dirname, '/../../expected/text-shaping-zero-width-space.json'))); - shaped = shaping.shapeText(Formatted.fromString('三三\u200b三三\u200b三三\u200b三三三三三三\u200b三三'), glyphs, fontStack, 5 * oneEm, oneEm, 'center', 'center', 0, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString('三三\u200b三三\u200b三三\u200b三三三三三三\u200b三三'), glyphs, fontStack, 5 * oneEm, oneEm, 'center', 'center', 0, [0, 0], WritingMode.horizontal, false, 'point'); if (UPDATE) fs.writeFileSync(path.join(__dirname, '/../../expected/text-shaping-zero-width-space.json'), JSON.stringify(shaped, null, 2)); t.deepEqual(shaped, expectedZeroWidthSpaceBreak); // Null shaping. - shaped = shaping.shapeText(Formatted.fromString(''), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString(''), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal, false, 'point'); t.equal(false, shaped); - shaped = shaping.shapeText(Formatted.fromString(String.fromCharCode(0)), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString(String.fromCharCode(0)), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal, false, 'point'); t.equal(false, shaped); // https://github.com/mapbox/mapbox-gl-js/issues/3254 - shaped = shaping.shapeText(Formatted.fromString(' foo bar\n'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal); - const shaped2 = shaping.shapeText(Formatted.fromString('foo bar'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal); + shaped = shaping.shapeText(Formatted.fromString(' foo bar\n'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal, false, 'point'); + const shaped2 = shaping.shapeText(Formatted.fromString('foo bar'), glyphs, fontStack, 15 * oneEm, oneEm, 'center', 'center', 0 * oneEm, [0, 0], WritingMode.horizontal, false, 'point'); t.same(shaped.positionedGlyphs, shaped2.positionedGlyphs); t.end();