diff --git a/cocos/2d/assembler/label/bmfont.ts b/cocos/2d/assembler/label/bmfont.ts index 78431f155a0..8865b66878b 100644 --- a/cocos/2d/assembler/label/bmfont.ts +++ b/cocos/2d/assembler/label/bmfont.ts @@ -50,68 +50,6 @@ export const bmfont: IAssembler = { // Fill All fillMeshVertices3D(node, renderer, comp.renderData!, tempColor); }, - - appendQuad (comp: Label, spriteFrame: SpriteFrame, rect: Rect, rotated: boolean, x: number, y: number, scale: number) { - const renderData = comp.renderData; - if (!renderData) { - return; - } - - const dataOffset = renderData.dataLength; - - renderData.dataLength += 4; - renderData.resize(renderData.dataLength, renderData.dataLength / 2 * 3); - - const dataList = renderData.data; - const texW = spriteFrame.width; - const texH = spriteFrame.height; - - const rectWidth = rect.width; - const rectHeight = rect.height; - - let l = 0; - let b = 0; - let t = 0; - let r = 0; - if (!rotated) { - l = (rect.x) / texW; - r = (rect.x + rectWidth) / texW; - b = (rect.y + rectHeight) / texH; - t = (rect.y) / texH; - - dataList[dataOffset].u = l; - dataList[dataOffset].v = b; - dataList[dataOffset + 1].u = r; - dataList[dataOffset + 1].v = b; - dataList[dataOffset + 2].u = l; - dataList[dataOffset + 2].v = t; - dataList[dataOffset + 3].u = r; - dataList[dataOffset + 3].v = t; - } else { - l = (rect.x) / texW; - r = (rect.x + rectHeight) / texW; - b = (rect.y + rectWidth) / texH; - t = (rect.y) / texH; - - dataList[dataOffset].u = l; - dataList[dataOffset].v = t; - dataList[dataOffset + 1].u = l; - dataList[dataOffset + 1].v = b; - dataList[dataOffset + 2].u = r; - dataList[dataOffset + 2].v = t; - dataList[dataOffset + 3].u = r; - dataList[dataOffset + 3].v = b; - } - - dataList[dataOffset].x = x; - dataList[dataOffset].y = y - rectHeight * scale; - dataList[dataOffset + 1].x = x + rectWidth * scale; - dataList[dataOffset + 1].y = y - rectHeight * scale; - dataList[dataOffset + 2].x = x; - dataList[dataOffset + 2].y = y; - dataList[dataOffset + 3].x = x + rectWidth * scale; - dataList[dataOffset + 3].y = y; - }, }; js.addon(bmfont, bmfontUtils); diff --git a/cocos/2d/assembler/label/bmfontUtils.ts b/cocos/2d/assembler/label/bmfontUtils.ts index 6a49f279eb9..8ec4ce1194f 100644 --- a/cocos/2d/assembler/label/bmfontUtils.ts +++ b/cocos/2d/assembler/label/bmfontUtils.ts @@ -24,12 +24,11 @@ import { JSB } from 'internal:constants'; import { error } from '@base/debug'; -import { IConfig, FontAtlas } from '../../assets/bitmap-font'; +import { FontAtlas, BitmapFont } from '../../assets/bitmap-font'; import { SpriteFrame } from '../../assets/sprite-frame'; -import { Rect } from '../../../core'; +import { Rect, Vec2 } from '../../../core'; import { Label, Overflow, CacheMode } from '../../components/label'; import { UITransform } from '../../framework/ui-transform'; -import { LetterAtlas, shareLabelInfo } from './font-utils'; import { dynamicAtlasManager } from '../../utils/dynamic-atlas/atlas-manager'; import { TextProcessing } from './text-processing'; import { TextOutputLayoutData, TextOutputRenderData } from './text-output-data'; @@ -37,56 +36,88 @@ import { TextStyle } from './text-style'; import { TextLayout } from './text-layout'; import { view } from '../../../ui/view'; -const _defaultLetterAtlas = new LetterAtlas(64, 64); const _defaultFontAtlas = new FontAtlas(null); -let _comp: Label | null = null; -let _uiTrans: UITransform | null = null; - -let _fntConfig: IConfig | null = null; -let _spriteFrame: SpriteFrame|null = null; -let QUAD_INDICES; +let QUAD_INDICES: Uint16Array | null = null; export const bmfontUtils = { - updateProcessingData (style: TextStyle, layout: TextLayout, - outputLayoutData: TextOutputLayoutData, outputRenderData: TextOutputRenderData, - comp: Label, trans: UITransform): void { - style.fontSize = comp.fontSize; - style.actualFontSize = comp.fontSize; - style.originFontSize = _fntConfig ? _fntConfig.fontSize : comp.fontSize; - layout.horizontalAlign = comp.horizontalAlign; - layout.verticalAlign = comp.verticalAlign; - layout.spacingX = comp.spacingX; + updateLayoutProcessingData ( + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + comp: Label, + trans: UITransform, + ): void { + style.fontSize = comp.fontSize; //both + style.actualFontSize = comp.fontSize; //both + layout.horizontalAlign = comp.horizontalAlign; //both + layout.verticalAlign = comp.verticalAlign; //both + layout.spacingX = comp.spacingX; // layout only const overflow = comp.overflow; - layout.overFlow = overflow; - layout.lineHeight = comp.lineHeight; outputLayoutData.nodeContentSize.width = trans.width; outputLayoutData.nodeContentSize.height = trans.height; + layout.overFlow = overflow; // both + layout.lineHeight = comp.lineHeight; // both // should wrap text if (overflow === Overflow.NONE) { - layout.wrapping = false; - outputLayoutData.nodeContentSize.width += shareLabelInfo.margin * 2; - outputLayoutData.nodeContentSize.height += shareLabelInfo.margin * 2; + layout.wrapping = false; // both } else if (overflow === Overflow.RESIZE_HEIGHT) { layout.wrapping = true; - outputLayoutData.nodeContentSize.height += shareLabelInfo.margin * 2; } else { layout.wrapping = comp.enableWrapText; } - outputRenderData.uiTransAnchorX = trans.anchorX; - outputRenderData.uiTransAnchorY = trans.anchorY; + const fontAsset = comp.font as BitmapFont; + style.fntConfig = fontAsset.fntConfig; // layout only + style.originFontSize = fontAsset.fntConfig?.fontSize; //both + style.fontAtlas = fontAsset.fontDefDictionary; + if (!style.fontAtlas) { + style.fontAtlas = _defaultFontAtlas; + } + + style.isOutlined = false; + style.outlineWidth = 0; + + style.hash = ''; + }, + + // render Only + updateRenderProcessingData ( + style: TextStyle, + outputRenderData: TextOutputRenderData, + comp: Label, + anchor: Readonly, + ): void { + // render info + outputRenderData.uiTransAnchorX = anchor.x; + outputRenderData.uiTransAnchorY = anchor.y; + + if (comp.font instanceof BitmapFont) { + const fontAsset = comp.font; + style.spriteFrame = fontAsset.spriteFrame; + dynamicAtlasManager.packToDynamicAtlas(comp, style.spriteFrame); + } + style.color.set(comp.color); // render only + }, + + updateLayoutData (comp: Label): void { + // Todo: dirtyFlag + const trans = comp.node._uiProps.uiTransformComp!; + const processing = TextProcessing.instance; + const style = comp.textStyle; + const layout = comp.textLayout; + const outputLayoutData = comp.textLayoutData; + style.fontScale = view.getScaleX(); - shareLabelInfo.lineHeight = comp.lineHeight; - shareLabelInfo.fontSize = comp.fontSize; + this.updateLayoutProcessingData(style, layout, outputLayoutData, comp, trans); - style.spriteFrame = _spriteFrame; - style.fntConfig = _fntConfig; - style.fontFamily = shareLabelInfo.fontFamily; + // TextProcessing + processing.processingString(true, style, layout, outputLayoutData, comp.string); - style.color.set(comp.color); + comp.actualFontSize = style.actualFontSize; + trans.setContentSize(outputLayoutData.nodeContentSize); }, updateRenderData (comp: Label): void { @@ -94,34 +125,29 @@ export const bmfontUtils = { return; } - if (_comp === comp) { return; } - if (comp.renderData.vertDirty) { - _comp = comp; - _uiTrans = _comp.node._uiProps.uiTransformComp!; + this.updateLayoutData(comp);// Todo: move to layout manager const renderData = comp.renderData; - const processing = TextProcessing.instance; const style = comp.textStyle; const layout = comp.textLayout; const outputLayoutData = comp.textLayoutData; const outputRenderData = comp.textRenderData; - style.fontScale = view.getScaleX(); - this._updateFontFamily(comp); - - this.updateProcessingData(style, layout, outputLayoutData, outputRenderData, comp, _uiTrans); + const anchor = comp.node._uiProps.uiTransformComp!.anchorPoint; + this.updateRenderProcessingData(style, outputRenderData, comp, anchor); - this._updateLabelInfo(comp); - - style.fontDesc = shareLabelInfo.fontDesc; - - // TextProcessing - processing.processingString(true, style, layout, outputLayoutData, comp.string); // generateVertex this.resetRenderData(comp); outputRenderData.quadCount = 0; - processing.generateRenderInfo(true, style, layout, outputLayoutData, outputRenderData, - comp.string, this.generateVertexData); + processing.generateRenderInfo( + true, + style, + layout, + outputLayoutData, + outputRenderData, + comp.string, + this.generateVertexData, + ); renderData.dataLength = outputRenderData.quadCount; renderData.resize(renderData.dataLength, renderData.dataLength / 2 * 3); @@ -132,17 +158,12 @@ export const bmfontUtils = { const indexCount = renderData.indexCount; this.createQuadIndices(indexCount); - renderData.chunk.setIndexBuffer(QUAD_INDICES); + renderData.chunk.setIndexBuffer(QUAD_INDICES!); - _comp.actualFontSize = style.actualFontSize; - _uiTrans.setContentSize(outputLayoutData.nodeContentSize); this.updateUVs(comp);// dirty need this.updateColor(comp); // dirty need renderData.vertDirty = false; - _comp = null; - - this._resetProperties(); } if (comp.spriteFrame) { @@ -195,8 +216,17 @@ export const bmfontUtils = { }, // callBack function - generateVertexData (style: TextStyle, outputLayoutData: TextOutputLayoutData, outputRenderData: TextOutputRenderData, offset: number, - spriteFrame: SpriteFrame, rect: Rect, rotated: boolean, x: number, y: number): void { + generateVertexData ( + style: TextStyle, + outputLayoutData: TextOutputLayoutData, + outputRenderData: TextOutputRenderData, + offset: number, + spriteFrame: SpriteFrame, + rect: Rect, + rotated: boolean, + x: number, + y: number, + ): void { const dataOffset = offset; const scale = style.bmfontScale; @@ -251,37 +281,7 @@ export const bmfontUtils = { dataList[dataOffset + 3].y = y; }, - _updateFontFamily (comp): void { - const fontAsset = comp.font; - _spriteFrame = fontAsset.spriteFrame; - _fntConfig = fontAsset.fntConfig; - shareLabelInfo.fontAtlas = fontAsset.fontDefDictionary; - if (!shareLabelInfo.fontAtlas) { - if (comp.cacheMode === CacheMode.CHAR) { - shareLabelInfo.fontAtlas = _defaultLetterAtlas; - } else { - shareLabelInfo.fontAtlas = _defaultFontAtlas; - } - } - - dynamicAtlasManager.packToDynamicAtlas(comp, _spriteFrame); - // TODO update material and uv - }, - - _updateLabelInfo (comp): void { - // clear - shareLabelInfo.hash = ''; - shareLabelInfo.margin = 0; - }, - - _resetProperties (): void { - _fntConfig = null; - _spriteFrame = null; - shareLabelInfo.hash = ''; - shareLabelInfo.margin = 0; - }, - - createQuadIndices (indexCount): void { + createQuadIndices (indexCount: number): void { if (indexCount % 6 !== 0) { error('illegal index count!'); return; diff --git a/cocos/2d/assembler/label/font-utils.ts b/cocos/2d/assembler/label/font-utils.ts index 251848eed96..a0bfce1d34b 100644 --- a/cocos/2d/assembler/label/font-utils.ts +++ b/cocos/2d/assembler/label/font-utils.ts @@ -22,8 +22,8 @@ THE SOFTWARE. */ -import { warn, warnID } from '@base/debug'; import { ccwindow } from '@base/global'; +import { warn, warnID } from '@base/debug'; import { FontAtlas } from '../../assets/bitmap-font'; import { Color, macro, ImageData } from '../../../core'; import { ImageAsset, Texture2D } from '../../../asset/assets'; @@ -31,6 +31,7 @@ import { PixelFormat } from '../../../asset/assets/asset-enum'; import { BufferTextureCopy } from '../../../gfx'; import { safeMeasureText, BASELINE_RATIO, MIDDLE_RATIO, getBaselineOffset } from '../../utils/text-utils'; import { director, Director } from '../../../game/director'; +import { TextStyle } from './text-style'; export interface ISharedLabelData { canvas: HTMLCanvasElement; @@ -88,12 +89,8 @@ export class CanvasPool { interface ILabelInfo { fontSize: number; - lineHeight: number; - hash: string; fontFamily: string; fontDesc: string; - hAlign: number; - vAlign: number; color: Color; isOutlined: boolean; out: Color; @@ -131,10 +128,10 @@ class LetterTexture { public height = 0; public offsetY = 0; public hash: string; - constructor (char: string, labelInfo: ILabelInfo) { + constructor (char: string, labelInfo: ILabelInfo, hash: string) { this.char = char; this.labelInfo = labelInfo; - this.hash = `${char.charCodeAt(0)}${labelInfo.hash}`; + this.hash = `${char.charCodeAt(0)}${hash}`; } public updateRenderData (): void { @@ -400,11 +397,22 @@ export class LetterAtlas { return this.fontDefDictionary.letterDefinitions[key]; } - public getLetterDefinitionForChar (char: string, labelInfo: ILabelInfo): any { - const hash = char.charCodeAt(0).toString() + labelInfo.hash; + public getLetterDefinitionForChar (char: string, style: TextStyle, fontScale: number): any { + const styleHash = style.hash; + const hash = char.charCodeAt(0).toString() + styleHash; let letter = this.fontDefDictionary.letterDefinitions[hash]; if (!letter) { - const temp = new LetterTexture(char, labelInfo); + const sharedLabelData: ILabelInfo = { + fontSize: style.fontSize, + fontFamily: style.fontFamily, + fontDesc: style.fontDesc, + color: style.color.clone(), + isOutlined: style.isOutlined, + out: style.outlineColor.clone(), + margin: style.outlineWidth, + fontScale, + }; + const temp = new LetterTexture(char, sharedLabelData, styleHash); temp.updateRenderData(); letter = this.insertLetterTexture(temp); temp.destroy(); @@ -414,45 +422,13 @@ export class LetterAtlas { } } -export interface IShareLabelInfo { - fontAtlas: FontAtlas | LetterAtlas | null; - fontSize: number; - lineHeight: number; - hAlign: number; - vAlign: number; - hash: string; - fontFamily: string; - fontDesc: string; - color: Color; - isOutlined: boolean; - out: Color; - margin: number; - fontScale: number; -} - -export const shareLabelInfo: IShareLabelInfo = { - fontAtlas: null, - fontSize: 0, - lineHeight: 0, - hAlign: 0, - vAlign: 0, - hash: '', - fontFamily: '', - fontDesc: 'Arial', - color: Color.WHITE.clone(), - isOutlined: false, - out: Color.WHITE.clone(), - margin: 0, - fontScale: 1, -}; - -export function computeHash (labelInfo: IShareLabelInfo): string { +export function computeHash (color: Color, isOutlined: boolean, margin: number, outlineColor: Color, fontSize: number, fontFamily: string): string { const hashData = ''; - const color = labelInfo.color.toHEX(); + const colorHex = color.toHEX(); let out = ''; - if (labelInfo.isOutlined && labelInfo.margin > 0) { - out = out + labelInfo.margin.toString() + labelInfo.out.toHEX(); + if (isOutlined && margin > 0) { + out = out + margin.toString() + outlineColor.toHEX(); } - return hashData + labelInfo.fontSize.toString() + labelInfo.fontFamily + color + out; + return hashData + fontSize.toString() + fontFamily + colorHex + out; } diff --git a/cocos/2d/assembler/label/letter-font.ts b/cocos/2d/assembler/label/letter-font.ts index c189b39fb2a..a9c8962b884 100644 --- a/cocos/2d/assembler/label/letter-font.ts +++ b/cocos/2d/assembler/label/letter-font.ts @@ -22,14 +22,18 @@ THE SOFTWARE. */ +import { TextureBase } from '../../../asset/assets/texture-base'; import { js } from '../../../core'; -import { Label, LabelOutline } from '../../components'; +import { Label, Overflow } from '../../components'; +import { UITransform } from '../../framework/ui-transform'; import { bmfontUtils } from './bmfontUtils'; -import { shareLabelInfo, LetterAtlas, computeHash, LetterRenderTexture } from './font-utils'; +import { LetterAtlas, computeHash } from './font-utils'; +import { TextLayout } from './text-layout'; +import { TextOutputLayoutData } from './text-output-data'; +import { TextStyle } from './text-style'; const _atlasWidth = 1024; const _atlasHeight = 1024; -const _isBold = false; let _shareAtlas: LetterAtlas | null = null; @@ -39,24 +43,7 @@ export const letterFont = js.mixin(bmfontUtils, { _shareAtlas = new LetterAtlas(_atlasWidth, _atlasHeight); } - return _shareAtlas.getTexture() as LetterRenderTexture | null; - }, - - _updateFontFamily (comp) { - shareLabelInfo.fontAtlas = _shareAtlas; - shareLabelInfo.fontFamily = this._getFontFamily(comp); - - // outline - const isOutlined = comp.enableOutline && comp.outlineWidth > 0; - if (isOutlined) { - shareLabelInfo.isOutlined = true; - shareLabelInfo.margin = comp.outlineWidth; - shareLabelInfo.out = comp.outlineColor.clone(); - shareLabelInfo.out.a = comp.outlineColor.color.a * comp.color.a / 255.0; - } else { - shareLabelInfo.isOutlined = false; - shareLabelInfo.margin = 0; - } + return _shareAtlas.getTexture() as TextureBase; }, _getFontFamily (comp: Label) { @@ -72,19 +59,66 @@ export const letterFont = js.mixin(bmfontUtils, { return fontFamily; }, - _updateLabelInfo (comp) { - shareLabelInfo.fontDesc = this._getFontDesc(); - shareLabelInfo.color = comp.color; - shareLabelInfo.hash = computeHash(shareLabelInfo); + _getFontDesc (fontSize: number, fontFamily: string) { + let fontDesc = `${fontSize.toString()}px `; + fontDesc += fontFamily; + + return fontDesc; }, - _getFontDesc () { - let fontDesc = `${shareLabelInfo.fontSize.toString()}px `; - fontDesc += shareLabelInfo.fontFamily; - if (_isBold) { - fontDesc = `bold ${fontDesc}`; + updateLayoutProcessingData ( + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + comp: Label, + trans: UITransform, + ): void { + style.fontSize = comp.fontSize; + style.actualFontSize = comp.fontSize; + layout.horizontalAlign = comp.horizontalAlign; + layout.verticalAlign = comp.verticalAlign; + layout.spacingX = comp.spacingX; + const overflow = comp.overflow; + + outputLayoutData.nodeContentSize.width = trans.width; + outputLayoutData.nodeContentSize.height = trans.height; + layout.overFlow = overflow; + layout.lineHeight = comp.lineHeight; + + style.fontAtlas = _shareAtlas; + style.fontFamily = this._getFontFamily(comp); + + // outline + let margin = 0; + const isOutlined = comp.enableOutline && comp.outlineWidth > 0; + if (isOutlined) { + style.isOutlined = true; + margin = comp.outlineWidth; + style.outlineWidth = comp.outlineWidth; + style.outlineColor = comp.outlineColor.clone(); + style.outlineColor.a = comp.outlineColor.a * comp.color.a / 255.0; + } else { + style.outlineWidth = 0; + style.isOutlined = false; + margin = 0; } - return fontDesc; + // should wrap text + if (overflow === Overflow.NONE) { + layout.wrapping = false; // both + outputLayoutData.nodeContentSize.width += margin * 2; + outputLayoutData.nodeContentSize.height += margin * 2; + } else if (overflow === Overflow.RESIZE_HEIGHT) { + layout.wrapping = true; + outputLayoutData.nodeContentSize.height += margin * 2; + } else { + layout.wrapping = comp.enableWrapText; + } + style.originFontSize = comp.fontSize; + style.fntConfig = null; + + style.fontDesc = this._getFontDesc(style.fontSize, style.fontFamily); + style.color.set(comp.color); + style.hash = computeHash(style.color, style.isOutlined, style.outlineWidth, style.outlineColor, style.fontSize, style.fontFamily); }, }); diff --git a/cocos/2d/assembler/label/text-output-data.ts b/cocos/2d/assembler/label/text-output-data.ts index 30086182eb3..10db72c3430 100644 --- a/cocos/2d/assembler/label/text-output-data.ts +++ b/cocos/2d/assembler/label/text-output-data.ts @@ -25,7 +25,7 @@ import { Texture2D } from '../../../asset/assets'; import { Rect, Size, Vec2 } from '../../../core'; import { SpriteFrame } from '../../assets'; -import { IRenderData } from './text-processing'; +import { IRenderData, LetterInfo } from './text-processing'; export class TextOutputLayoutData { // public parsedStringStyle; // Prepare for merging richtext @@ -43,6 +43,8 @@ export class TextOutputLayoutData { public startPosition = Vec2.ZERO.clone(); // ttf + public lettersInfo: LetterInfo[] = []; // only bmfont use + public reset (): void { this.parsedString.length = 0; this.nodeContentSize.set(0, 0); @@ -50,6 +52,7 @@ export class TextOutputLayoutData { this.canvasPadding.set(); this.contentSizeExtend.set(); this.startPosition.set(); + this.lettersInfo.length = 0; } } diff --git a/cocos/2d/assembler/label/text-processing.ts b/cocos/2d/assembler/label/text-processing.ts index 7aaab7f0d4d..05acfcb1ded 100644 --- a/cocos/2d/assembler/label/text-processing.ts +++ b/cocos/2d/assembler/label/text-processing.ts @@ -26,12 +26,12 @@ import { cclegacy } from '@base/global'; import { log, logID, warn } from '@base/debug'; import { Texture2D } from '../../../asset/assets'; import { WrapMode } from '../../../asset/assets/asset-enum'; -import { Color, Pool, Rect, Vec2 } from '../../../core'; +import { Color, Rect, Vec2 } from '../../../core'; import { SpriteFrame } from '../../assets'; import { FontLetterDefinition } from '../../assets/bitmap-font'; import { HorizontalTextAlignment, Overflow, VerticalTextAlignment } from '../../components/label'; import { BASELINE_RATIO, fragmentText, getBaselineOffset, isUnicodeCJK, isUnicodeSpace, safeMeasureText } from '../../utils/text-utils'; -import { CanvasPool, ISharedLabelData, shareLabelInfo } from './font-utils'; +import { CanvasPool, ISharedLabelData } from './font-utils'; import { TextOutputLayoutData, TextOutputRenderData } from './text-output-data'; import { TextStyle } from './text-style'; import { TextLayout } from './text-layout'; @@ -55,7 +55,7 @@ export interface IRenderData { color: Color; } -class LetterInfo { +export class LetterInfo { public char = ''; public valid = true; public x = 0; @@ -75,11 +75,16 @@ export class TextProcessing { public destroy (): void { CanvasPool.getInstance().put(this._canvasData!); - this._lettersInfo.length = 0; } - public processingString (isBmFont: boolean, style: TextStyle, layout: TextLayout, - outputLayoutData: TextOutputLayoutData, inputString: string, out?: string[]): void { + public processingString ( + isBmFont: boolean, + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + inputString: string, + out?: string[], + ): void { if (!isBmFont) { let loopTime = 0; this._fontScale = this._getStyleFontScale(style.fontSize, style.fontScale); @@ -92,7 +97,10 @@ export class TextProcessing { if (loopTime > MAX_CALCULATION_NUM) { this._fontScale = 1; } else { - const maxValue = Math.max(outputLayoutData.canvasSize.width, outputLayoutData.canvasSize.height); // Current Canvas Size max dimension + const maxValue = Math.max( + outputLayoutData.canvasSize.width, + outputLayoutData.canvasSize.height, + ); // Current Canvas Size max dimension const canvasScaleToMaxSizeRatio = MAX_SIZE / maxValue; this._fontScale *= canvasScaleToMaxSizeRatio; this._fontScale = Math.max(1, this._fontScale); @@ -107,7 +115,6 @@ export class TextProcessing { } else { this._fontScale = 1; } - shareLabelInfo.fontScale = this._fontScale; this._setupBMFontOverflowMetrics(layout, outputLayoutData); this._updateFontScale(style); this._computeHorizontalKerningForText(style, layout, inputString); @@ -118,8 +125,15 @@ export class TextProcessing { } } - public generateRenderInfo (isBmFont: boolean, style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, - outputRenderData: TextOutputRenderData, inputString: string, callback: AnyFunction): void { + public generateRenderInfo ( + isBmFont: boolean, + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + outputRenderData: TextOutputRenderData, + inputString: string, + callback: AnyFunction, + ): void { if (!isBmFont) { this._updateLabelDimensions(style, layout, outputLayoutData); this._updateTexture(style, layout, outputLayoutData, outputRenderData); @@ -143,7 +157,6 @@ export class TextProcessing { private _canvas: HTMLCanvasElement | null = null; private _canvasData: ISharedLabelData | null = null; - private _lettersInfo: LetterInfo[] = []; private _tmpRect = new Rect(); private _maxFontSize = 100; @@ -158,8 +171,13 @@ export class TextProcessing { return scale; } - private _calculateLabelFont (style: TextStyle, layout: TextLayout, - outputLayoutData: TextOutputLayoutData, inputString: string): void { + // processingString + private _calculateLabelFont ( + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + inputString: string, + ): void { if (!this._context) { return; } @@ -292,10 +310,12 @@ export class TextProcessing { totalHeight = 0; for (i = 0; i < paragraphedStrings.length; ++i) { const allWidth = safeMeasureText(this._context, paragraphedStrings[i], _fontDesc); - textFragment = fragmentText(paragraphedStrings[i], + textFragment = fragmentText( + paragraphedStrings[i], allWidth, canvasWidthNoMargin, - this._measureText(this._context, _fontDesc)); + this._measureText(this._context, _fontDesc), + ); totalHeight += textFragment.length * lineHeight; } @@ -342,17 +362,19 @@ export class TextProcessing { this._context.font = _fontDesc; for (let i = 0; i < paragraphedStrings.length; ++i) { const allWidth = safeMeasureText(this._context, paragraphedStrings[i], _fontDesc); - const textFragment = fragmentText(paragraphedStrings[i], + const textFragment = fragmentText( + paragraphedStrings[i], allWidth, canvasWidthNoMargin, - this._measureText(this._context, _fontDesc)); + this._measureText(this._context, _fontDesc), + ); _splitStrings = _splitStrings.concat(textFragment); } outputLayoutData.parsedString = _splitStrings; style.fontDesc = _fontDesc; } - private _measureText (ctx: CanvasRenderingContext2D, fontDesc): (str: string) => number { + private _measureText (ctx: CanvasRenderingContext2D, fontDesc: string): (str: string) => number { return (str: string): number => safeMeasureText(ctx, str, fontDesc); } @@ -367,6 +389,7 @@ export class TextProcessing { return paragraphLength; } + // processingString private _updatePaddingRect (style: TextStyle, outputLayoutData: TextOutputLayoutData): void { let top = 0; let bottom = 0; let left = 0; let right = 0; let outlineWidth = 0; @@ -416,9 +439,9 @@ export class TextProcessing { private _calculateFillTextStartPosition (style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData): void { let labelX = 0; - if (layout.horizontalAlign === HorizontalTextAlignment.RIGHT) { + if (layout.horizontalAlign === HorizontalTextAlignment.RIGHT as number) { labelX = outputLayoutData.canvasSize.width - outputLayoutData.canvasPadding.width; - } else if (layout.horizontalAlign === HorizontalTextAlignment.CENTER) { + } else if (layout.horizontalAlign === HorizontalTextAlignment.CENTER as number) { labelX = (outputLayoutData.canvasSize.width - outputLayoutData.canvasPadding.width) / 2; } @@ -426,10 +449,10 @@ export class TextProcessing { const drawStartY = lineHeight * (outputLayoutData.parsedString.length - 1); // TOP let firstLinelabelY = style.actualFontSize * (1 - BASELINE_RATIO / 2); - if (layout.verticalAlign !== VerticalTextAlignment.TOP) { + if (layout.verticalAlign !== VerticalTextAlignment.TOP as number) { // free space in vertical direction let blank = drawStartY + outputLayoutData.canvasPadding.height + style.actualFontSize - outputLayoutData.canvasSize.height; - if (layout.verticalAlign === VerticalTextAlignment.BOTTOM) { + if (layout.verticalAlign === VerticalTextAlignment.BOTTOM as number) { // Unlike BMFont, needs to reserve space below. blank += BASELINE_RATIO / 2 * style.actualFontSize; // BOTTOM @@ -556,9 +579,9 @@ export class TextProcessing { if (style.isUnderline) { const _drawUnderlineWidth = measureText(outputLayoutData.parsedString[i]); const _drawUnderlinePos = new Vec2(); - if (layout.horizontalAlign === HorizontalTextAlignment.RIGHT) { + if (layout.horizontalAlign === HorizontalTextAlignment.RIGHT as number) { _drawUnderlinePos.x = startPosition.x - _drawUnderlineWidth; - } else if (layout.horizontalAlign === HorizontalTextAlignment.CENTER) { + } else if (layout.horizontalAlign === HorizontalTextAlignment.CENTER as number) { _drawUnderlinePos.x = startPosition.x - (_drawUnderlineWidth / 2); } else { _drawUnderlinePos.x = startPosition.x; @@ -588,8 +611,15 @@ export class TextProcessing { // -------------------- Render Processing Part -------------------------- - private generateVertexData (isBmFont: boolean, style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, - outputRenderData: TextOutputRenderData, inputString: string, callback: AnyFunction): void { + private generateVertexData ( + isBmFont: boolean, + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + outputRenderData: TextOutputRenderData, + inputString: string, + callback: AnyFunction, + ): void { if (!isBmFont) { this.updateQuatCount(outputRenderData); // update vbBuffer count callback(style, outputLayoutData, outputRenderData); @@ -620,15 +650,16 @@ export class TextProcessing { // -------------------- Canvas Mode Part --------------------------- // -------------------- Multiple Quad Mode Part -------------------- + // processingString private _setupBMFontOverflowMetrics (layout: TextLayout, outputLayoutData: TextOutputLayoutData): void { let newWidth = outputLayoutData.nodeContentSize.width; let newHeight = outputLayoutData.nodeContentSize.height; - if (layout.overFlow === Overflow.RESIZE_HEIGHT) { + if (layout.overFlow === Overflow.RESIZE_HEIGHT as number) { newHeight = 0; } - if (layout.overFlow === Overflow.NONE) { + if (layout.overFlow === Overflow.NONE as number) { newWidth = 0; newHeight = 0; } @@ -669,11 +700,12 @@ export class TextProcessing { } } + // processingString private _alignText (style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, inputString: string): void { this._multilineTextWrap(style, layout, outputLayoutData, inputString, this._getFirstWordLen); // shrink - if (layout.overFlow === Overflow.SHRINK) { + if (layout.overFlow === Overflow.SHRINK as number) { if (style.fontSize > 0 && this._isVerticalClamp(style, layout, outputLayoutData, inputString, this)) { this._shrinkLabelToContentSize(style, layout, outputLayoutData, inputString, this._isVerticalClamp); } @@ -689,7 +721,7 @@ export class TextProcessing { let textFragment = ''; for (let i = 0, line = 0, l = inputString.length; i < l; ++i) { - const letterInfo = this._lettersInfo[i]; + const letterInfo = outputLayoutData.lettersInfo[i]; if (!letterInfo.valid) { continue; } if (line === letterInfo.line) { textFragment += letterInfo.char; @@ -703,8 +735,14 @@ export class TextProcessing { outputLayoutData.parsedString = _splitStrings; } - private _multilineTextWrap (style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, - inputString: string, nextTokenFunc: (arg0: TextStyle, arg1: TextLayout, arg2: string, arg3: number, arg4: number) => number): boolean { + // processingString + private _multilineTextWrap ( + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + inputString: string, + nextTokenFunc: (arg0: TextStyle, arg1: TextLayout, arg2: string, arg3: number, arg4: number, arg5: number) => number, + ): boolean { layout.linesWidth.length = 0; const _string = inputString; @@ -730,12 +768,12 @@ export class TextProcessing { lineIndex++; nextTokenX = 0; nextTokenY -= layout.lineHeight * this._getFontScale(style, layout) + _lineSpacing; - this._recordPlaceholderInfo(index, character); + this._recordPlaceholderInfo(index, character, style.hash, outputLayoutData.lettersInfo); index++; continue; } - const tokenLen = nextTokenFunc(style, layout, _string, index, textLen); + const tokenLen = nextTokenFunc(style, layout, _string, index, textLen, this._fontScale); let tokenHighestY = highestY; let tokenLowestY = lowestY; let tokenRight = letterRight; @@ -747,18 +785,18 @@ export class TextProcessing { const letterIndex = index + tmp; character = _string.charAt(letterIndex); if (character === '\r') { - this._recordPlaceholderInfo(letterIndex, character); + this._recordPlaceholderInfo(letterIndex, character, style.hash, outputLayoutData.lettersInfo); continue; } - letterDef = shareLabelInfo.fontAtlas!.getLetterDefinitionForChar(character, shareLabelInfo); + letterDef = style.fontAtlas!.getLetterDefinitionForChar(character, style, this._fontScale); if (!letterDef) { - this._recordPlaceholderInfo(letterIndex, character); + this._recordPlaceholderInfo(letterIndex, character, style.hash, outputLayoutData.lettersInfo); log(`Can't find letter definition in texture atlas ${ style.fntConfig!.atlasName} for letter:${character}`); continue; } - const letterX = nextLetterX + letterDef.offsetX * style.bmfontScale - shareLabelInfo.margin; + const letterX = nextLetterX + letterDef.offsetX * style.bmfontScale - style.outlineWidth; if (layout.wrapping && layout.maxLineWidth > 0 @@ -777,7 +815,7 @@ export class TextProcessing { } letterPosition.y = nextTokenY - letterDef.offsetY * style.bmfontScale; - this._recordLetterInfo(letterPosition, character, letterIndex, lineIndex); + this._recordLetterInfo(letterPosition, character, letterIndex, lineIndex, style.hash, style.fontAtlas, outputLayoutData.lettersInfo); if (letterIndex + 1 < layout.horizontalKerning.length && letterIndex < textLen - 1) { nextLetterX += layout.horizontalKerning[letterIndex + 1] * style.bmfontScale; @@ -825,10 +863,10 @@ export class TextProcessing { outputLayoutData.nodeContentSize.width = layout.textWidthTemp; outputLayoutData.nodeContentSize.height = layout.textHeightTemp; if (layout.textWidthTemp <= 0) { - outputLayoutData.nodeContentSize.width = parseFloat(longestLine.toFixed(2)) + shareLabelInfo.margin * 2; + outputLayoutData.nodeContentSize.width = parseFloat(longestLine.toFixed(2)) + style.outlineWidth * 2; } if (layout.textHeightTemp <= 0) { - outputLayoutData.nodeContentSize.height = parseFloat(layout.textDesiredHeight.toFixed(2)) + shareLabelInfo.margin * 2; + outputLayoutData.nodeContentSize.height = parseFloat(layout.textDesiredHeight.toFixed(2)) + style.outlineWidth * 2; } layout.tailoredTopY = outputLayoutData.nodeContentSize.height; @@ -843,35 +881,44 @@ export class TextProcessing { return true; } - private _recordPlaceholderInfo (letterIndex: number, char: string): void { - if (letterIndex >= this._lettersInfo.length) { + private _recordPlaceholderInfo (letterIndex: number, char: string, hash: string, lettersInfo: LetterInfo[]): void { + if (letterIndex >= lettersInfo.length) { const tmpInfo = new LetterInfo(); - this._lettersInfo.push(tmpInfo); + lettersInfo.push(tmpInfo); } - this._lettersInfo[letterIndex].char = char; - this._lettersInfo[letterIndex].hash = `${char.charCodeAt(0)}${shareLabelInfo.hash}`; - this._lettersInfo[letterIndex].valid = false; + lettersInfo[letterIndex].char = char; + lettersInfo[letterIndex].hash = `${char.charCodeAt(0)}${hash}`; + lettersInfo[letterIndex].valid = false; } - private _recordLetterInfo (letterPosition: Vec2, character: string, letterIndex: number, lineIndex: number): void { - if (letterIndex >= this._lettersInfo.length) { + private _recordLetterInfo ( + letterPosition: Vec2, + character: string, + letterIndex: number, + lineIndex: number, + hash: string, + fontAtlas, + lettersInfo, + ): void { + if (letterIndex >= lettersInfo.length) { const tmpInfo = new LetterInfo(); - this._lettersInfo.push(tmpInfo); + lettersInfo.push(tmpInfo); } const char = character.charCodeAt(0); - const key = `${char}${shareLabelInfo.hash}`; - - this._lettersInfo[letterIndex].line = lineIndex; - this._lettersInfo[letterIndex].char = character; - this._lettersInfo[letterIndex].hash = key; - this._lettersInfo[letterIndex].valid = shareLabelInfo.fontAtlas!.getLetter(key).valid; - this._lettersInfo[letterIndex].x = letterPosition.x; - this._lettersInfo[letterIndex].y = letterPosition.y; + const key = `${char}${hash}`; + + lettersInfo[letterIndex].line = lineIndex; + lettersInfo[letterIndex].char = character; + lettersInfo[letterIndex].hash = key; + lettersInfo[letterIndex].valid = fontAtlas.getLetter(key).valid; + lettersInfo[letterIndex].x = letterPosition.x; + lettersInfo[letterIndex].y = letterPosition.y; } - private _getFirstWordLen (style: TextStyle, layout: TextLayout, text: string, startIndex: number, textLen: number): number { + // processingString + private _getFirstWordLen (style: TextStyle, layout: TextLayout, text: string, startIndex: number, textLen: number, fontScale: number): number { let character = text.charAt(startIndex); if (isUnicodeCJK(character) || character === '\n' @@ -880,7 +927,7 @@ export class TextProcessing { } let len = 1; - let letterDef = shareLabelInfo.fontAtlas!.getLetterDefinitionForChar(character, shareLabelInfo); + let letterDef = style.fontAtlas!.getLetterDefinitionForChar(character, style, fontScale); if (!letterDef) { return len; } @@ -889,12 +936,11 @@ export class TextProcessing { for (let index = startIndex + 1; index < textLen; ++index) { character = text.charAt(index); - letterDef = shareLabelInfo.fontAtlas!.getLetterDefinitionForChar(character, shareLabelInfo); + letterDef = style.fontAtlas!.getLetterDefinitionForChar(character, style, fontScale); if (!letterDef) { break; } letterX = nextLetterX + letterDef.offsetX * style.bmfontScale; - if (letterX + letterDef.w * style.bmfontScale > layout.maxLineWidth && !isUnicodeSpace(character) && layout.maxLineWidth > 0) { @@ -908,7 +954,6 @@ export class TextProcessing { } len++; } - return len; } @@ -938,10 +983,10 @@ export class TextProcessing { // TOP layout.letterOffsetY = outputLayoutData.nodeContentSize.height; - if (layout.verticalAlign !== VerticalTextAlignment.TOP) { + if (layout.verticalAlign !== VerticalTextAlignment.TOP as number) { const blank = outputLayoutData.nodeContentSize.height - layout.textDesiredHeight + layout.lineHeight * this._getFontScale(style, layout) - style.originFontSize * this._fontScale * style.bmfontScale; - if (layout.verticalAlign === VerticalTextAlignment.BOTTOM) { + if (layout.verticalAlign === VerticalTextAlignment.BOTTOM as number) { // BOTTOM layout.letterOffsetY -= blank; } else { @@ -952,11 +997,16 @@ export class TextProcessing { } private _getFontScale (style: TextStyle, layout: TextLayout): number { - return layout.overFlow === Overflow.SHRINK ? style.bmfontScale : 1; + return layout.overFlow === Overflow.SHRINK as number ? style.bmfontScale : 1; } - private _isVerticalClamp (style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, - inputString: string, process: TextProcessing): boolean { + private _isVerticalClamp ( + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + inputString: string, + process: TextProcessing, + ): boolean { if (layout.textDesiredHeight > outputLayoutData.nodeContentSize.height) { return true; } else { @@ -964,18 +1014,22 @@ export class TextProcessing { } } - private _isHorizontalClamp (style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, - inputString: string, process: TextProcessing): boolean { + private _isHorizontalClamp ( + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + inputString: string, + process: TextProcessing, + ): boolean { let letterClamp = false; const _string = inputString; for (let ctr = 0, l = _string.length; ctr < l; ++ctr) { - const letterInfo = process._lettersInfo[ctr]; + const letterInfo = outputLayoutData.lettersInfo[ctr]; if (letterInfo.valid) { - const letterDef = shareLabelInfo.fontAtlas!.getLetterDefinitionForChar(letterInfo.char, shareLabelInfo); + const letterDef = style.fontAtlas!.getLetterDefinitionForChar(letterInfo.char, style, process._fontScale); if (!letterDef) { continue; } - const px = letterInfo.x + letterDef.w * style.bmfontScale; const lineIndex = letterInfo.line; if (layout.textWidthTemp > 0) { @@ -994,7 +1048,6 @@ export class TextProcessing { } } } - return letterClamp; } @@ -1007,9 +1060,15 @@ export class TextProcessing { return false; } - private _shrinkLabelToContentSize (style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, inputString: string, + // processingString + private _shrinkLabelToContentSize ( + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + inputString: string, lambda: (style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, - inputString: string, process: TextProcessing) => boolean): void { + inputString: string, process: TextProcessing) => boolean, + ): void { const fontSize = style.actualFontSize; let left = 0; @@ -1041,6 +1100,7 @@ export class TextProcessing { } } + // processingString private _scaleFontSizeDown (style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, inputString: string, fontSize: number): void { let shouldUpdateContent = true; if (!fontSize) { @@ -1055,18 +1115,24 @@ export class TextProcessing { } } - private _updateQuads (style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, - outputRenderData: TextOutputRenderData, inputString: string, callback): boolean { - const texture = style.spriteFrame ? style.spriteFrame.texture : shareLabelInfo.fontAtlas!.getTexture(); + private _updateQuads ( + style: TextStyle, + layout: TextLayout, + outputLayoutData: TextOutputLayoutData, + outputRenderData: TextOutputRenderData, + inputString: string, + callback, + ): boolean { + const texture = style.spriteFrame ? style.spriteFrame.texture : style.fontAtlas!.getTexture(); const appX = outputRenderData.uiTransAnchorX * outputLayoutData.nodeContentSize.width; const appY = outputRenderData.uiTransAnchorY * outputLayoutData.nodeContentSize.height; const ret = true; for (let ctr = 0, l = inputString.length; ctr < l; ++ctr) { - const letterInfo = this._lettersInfo[ctr]; + const letterInfo = outputLayoutData.lettersInfo[ctr]; if (!letterInfo.valid) { continue; } - const letterDef = shareLabelInfo.fontAtlas!.getLetter(letterInfo.hash); + const letterDef = style.fontAtlas!.getLetter(letterInfo.hash); if (!letterDef) { warn('Can\'t find letter in this bitmap-font'); continue; @@ -1087,7 +1153,7 @@ export class TextProcessing { py -= clipTop; } - if ((py - this._tmpRect.height * style.bmfontScale < layout.tailoredBottomY) && layout.overFlow === Overflow.CLAMP) { + if ((py - this._tmpRect.height * style.bmfontScale < layout.tailoredBottomY) && layout.overFlow === Overflow.CLAMP as number) { this._tmpRect.height = (py < layout.tailoredBottomY) ? 0 : (py - layout.tailoredBottomY) / style.bmfontScale; } } @@ -1097,7 +1163,7 @@ export class TextProcessing { if (layout.textWidthTemp > 0) { if (this._isHorizontalClamped(layout, outputLayoutData, px, lineIndex)) { - if (layout.overFlow === Overflow.CLAMP) { + if (layout.overFlow === Overflow.CLAMP as number) { this._tmpRect.width = 0; } } diff --git a/cocos/2d/assembler/label/text-style.ts b/cocos/2d/assembler/label/text-style.ts index 590f4c03842..b665da041ff 100644 --- a/cocos/2d/assembler/label/text-style.ts +++ b/cocos/2d/assembler/label/text-style.ts @@ -23,8 +23,9 @@ */ import { Color } from '../../../core'; -import { IConfig } from '../../assets/bitmap-font'; +import { FontAtlas, IConfig } from '../../assets/bitmap-font'; import { SpriteFrame } from '../../assets/sprite-frame'; +import { LetterAtlas } from './font-utils'; export class TextStyle { // ---------------ttf extra part----------------- @@ -67,6 +68,8 @@ export class TextStyle { // font info // todo remove public fntConfig: IConfig | null = null; // For char mode,not have asset public spriteFrame: SpriteFrame | null = null; // For char mode,not have spriteFrame in asset + public hash = ''; // For char mode,not have hash in asset + public fontAtlas: FontAtlas | LetterAtlas | null = null; // Just for bm & char public fontScale = 1; diff --git a/cocos/2d/assembler/label/ttfUtils.ts b/cocos/2d/assembler/label/ttfUtils.ts index c4ff09c4aa0..67655b67c41 100644 --- a/cocos/2d/assembler/label/ttfUtils.ts +++ b/cocos/2d/assembler/label/ttfUtils.ts @@ -31,42 +31,37 @@ import { TextStyle } from './text-style'; import { TextLayout } from './text-layout'; import { view } from '../../../ui/view'; import { approx } from '../../../core'; +import { Vec2 } from '../../../core/math'; const Overflow = Label.Overflow; export const ttfUtils = { - updateProcessingData ( + updateLayoutProcessingData ( style: TextStyle, layout: TextLayout, outputLayoutData: TextOutputLayoutData, - outputRenderData: TextOutputRenderData, comp: Label, trans: UITransform, ): void { // font info // both - style.isSystemFontUsed = comp.useSystemFont; - style.fontSize = comp.fontSize; + style.isSystemFontUsed = comp.useSystemFont; // both + style.fontSize = comp.fontSize; // both - // node info // both - outputLayoutData.nodeContentSize.width = outputLayoutData.canvasSize.width = trans.width; - outputLayoutData.nodeContentSize.height = outputLayoutData.canvasSize.height = trans.height; // layout info layout.lineHeight = comp.lineHeight; // both - layout.overFlow = comp.overflow; // layout only // but change render + layout.overFlow = comp.overflow; // layout only if (comp.overflow === Overflow.NONE) { layout.wrapping = false; } else if (comp.overflow === Overflow.RESIZE_HEIGHT) { layout.wrapping = true; } else { - layout.wrapping = comp.enableWrapText; // layout only // but change render + layout.wrapping = comp.enableWrapText; // layout only } // effect info // both style.isBold = comp.isBold; style.isItalic = comp.isItalic; - style.isUnderline = comp.isUnderline; - style.underlineHeight = comp.underlineHeight; // outline// both const isOutlined = comp.enableOutline && comp.outlineWidth > 0; @@ -90,14 +85,29 @@ export const ttfUtils = { style.hasShadow = false; } - // render info - style.color.set(comp.color);// may opacity bug // render Only - outputRenderData.texture = comp.spriteFrame; // render Only - outputRenderData.uiTransAnchorX = trans.anchorX; // render Only - outputRenderData.uiTransAnchorY = trans.anchorY; // render Only + layout.horizontalAlign = comp.horizontalAlign; // both + layout.verticalAlign = comp.verticalAlign; // both - layout.horizontalAlign = comp.horizontalAlign; // render Only - layout.verticalAlign = comp.verticalAlign; // render Only + // node info // both + outputLayoutData.nodeContentSize.width = outputLayoutData.canvasSize.width = trans.width; + outputLayoutData.nodeContentSize.height = outputLayoutData.canvasSize.height = trans.height; + }, + + // render Only + updateRenderProcessingData ( + style: TextStyle, + outputRenderData: TextOutputRenderData, + comp: Label, + anchor: Readonly, + ): void { + style.isUnderline = comp.isUnderline; + style.underlineHeight = comp.underlineHeight; + + // render info + style.color.set(comp.color); + outputRenderData.texture = comp.spriteFrame; + outputRenderData.uiTransAnchorX = anchor.x; + outputRenderData.uiTransAnchorY = anchor.y; }, getAssemblerData (): ISharedLabelData { @@ -112,42 +122,50 @@ export const ttfUtils = { } }, - updateRenderData (comp: Label): void { - if (!comp.renderData) { return; } - - if (comp.renderData.vertDirty) { + updateLayoutData (comp: Label): void { + // Todo: dirtyFlag + if (comp.assemblerData) { const trans = comp.node._uiProps.uiTransformComp!; const processing = TextProcessing.instance; const style = comp.textStyle; const layout = comp.textLayout; const outputLayoutData = comp.textLayoutData; - const outputRenderData = comp.textRenderData; style.fontScale = view.getScaleX(); - this.updateProcessingData(style, layout, outputLayoutData, outputRenderData, comp, trans); + this.updateLayoutProcessingData(style, layout, outputLayoutData, comp, trans); // use canvas in assemblerData // to do to optimize - processing.setCanvasUsed(comp.assemblerData!.canvas, comp.assemblerData!.context); + processing.setCanvasUsed(comp.assemblerData.canvas, comp.assemblerData.context); style.fontFamily = this._updateFontFamily(comp); - this._resetDynamicAtlas(comp); // TextProcessing processing.processingString(false, style, layout, outputLayoutData, comp.string); - processing.generateRenderInfo( - false, - style, - layout, - outputLayoutData, - outputRenderData, - comp.string, - this.generateVertexData, - ); + comp.actualFontSize = style.actualFontSize; + trans.setContentSize(outputLayoutData.nodeContentSize); + comp.contentWidth = outputLayoutData.nodeContentSize.width; + } + }, + + updateRenderData (comp: Label): void { + if (!comp.renderData) { return; } + + if (comp.renderData.vertDirty) { + this.updateLayoutData(comp);// Todo: move to layout manager + const processing = TextProcessing.instance; + const style = comp.textStyle; + const layout = comp.textLayout; + const outputLayoutData = comp.textLayoutData; + const outputRenderData = comp.textRenderData; + const anchor = comp.node._uiProps.uiTransformComp!.anchorPoint; + this.updateRenderProcessingData(style, outputRenderData, comp, anchor); + + this._resetDynamicAtlas(comp); + + processing.setCanvasUsed(comp.assemblerData!.canvas, comp.assemblerData!.context); + processing.generateRenderInfo(false, style, layout, outputLayoutData, outputRenderData, comp.string, this.generateVertexData); const renderData = comp.renderData; renderData.textureDirty = true; this._calDynamicAtlas(comp, outputLayoutData); - comp.actualFontSize = style.actualFontSize; - trans.setContentSize(outputLayoutData.nodeContentSize); - const datalist = renderData.data; datalist[0] = outputRenderData.vertexBuffer[0]; datalist[1] = outputRenderData.vertexBuffer[1]; @@ -156,7 +174,6 @@ export const ttfUtils = { this.updateUVs(comp); comp.renderData.vertDirty = false; - comp.contentWidth = outputLayoutData.nodeContentSize.width; } if (comp.spriteFrame) { diff --git a/cocos/2d/components/rich-text.ts b/cocos/2d/components/rich-text.ts index c0ed9d7cc9e..b0e3c8ba407 100644 --- a/cocos/2d/components/rich-text.ts +++ b/cocos/2d/components/rich-text.ts @@ -25,8 +25,8 @@ import { ccclass, executeInEditMode, executionOrder, help, menu, tooltip, multiline, type, displayOrder, serializable } from 'cc.decorator'; import { DEBUG, DEV, EDITOR } from 'internal:constants'; -import { assert, warnID } from '@base/debug'; import { cclegacy } from '@base/global'; +import { assert, warnID } from '@base/debug'; import { Font, SpriteAtlas, TTFFont, SpriteFrame } from '../assets'; import { EventTouch } from '../../input/types'; import { Color, Vec2, CCObject, js, Size } from '../../core'; @@ -897,8 +897,12 @@ export class RichText extends Component { } } if (fragmentWidth > this._maxWidth) { - const fragments = fragmentText(labelString, fragmentWidth, this._maxWidth, - this._measureText(styleIndex) as unknown as (s: string) => number); + const fragments = fragmentText( + labelString, + fragmentWidth, + this._maxWidth, + this._measureText(styleIndex) as unknown as (s: string) => number, + ); for (let k = 0; k < fragments.length; ++k) { const splitString = fragments[k]; labelSegment = this._addLabelSegment(splitString, styleIndex); @@ -1203,9 +1207,11 @@ export class RichText extends Component { } const pos = segment.node.position; - segment.node.setPosition(nextTokenX + lineOffsetX, + segment.node.setPosition( + nextTokenX + lineOffsetX, this._lineHeight * (totalLineCount - lineCount) - this._labelHeight * anchorY, - pos.z); + pos.z, + ); if (lineCount === nextLineIndex) { nextTokenX += segment.node._uiProps.uiTransformComp!.width;