@eva/plugin-renderer-text 2.1.0-beta.13 → 2.1.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EVA.plugin.renderer.text.js +312 -112
- package/dist/EVA.plugin.renderer.text.min.js +1 -1
- package/dist/plugin-renderer-text.cjs.js +373 -119
- package/dist/plugin-renderer-text.cjs.prod.js +1 -1
- package/dist/plugin-renderer-text.d.ts +18 -0
- package/dist/plugin-renderer-text.esm.js +376 -122
- package/package.json +5 -5
|
@@ -22,6 +22,18 @@ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
22
22
|
PERFORMANCE OF THIS SOFTWARE.
|
|
23
23
|
***************************************************************************** */
|
|
24
24
|
|
|
25
|
+
function __rest(s, e) {
|
|
26
|
+
var t = {};
|
|
27
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
28
|
+
t[p] = s[p];
|
|
29
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
30
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
31
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
32
|
+
t[p[i]] = s[p[i]];
|
|
33
|
+
}
|
|
34
|
+
return t;
|
|
35
|
+
}
|
|
36
|
+
|
|
25
37
|
function __decorate(decorators, target, key, desc) {
|
|
26
38
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
27
39
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -608,105 +620,261 @@ let Text = class Text extends pluginRenderer.Renderer {
|
|
|
608
620
|
constructor() {
|
|
609
621
|
super(...arguments);
|
|
610
622
|
this.name = 'Text';
|
|
623
|
+
this.presentationAddFlushEnabled = true;
|
|
611
624
|
this.texts = {};
|
|
625
|
+
this.retired = false;
|
|
626
|
+
this.pendingHTMLTextComponents = {};
|
|
627
|
+
this.fontIdentityIds = new WeakMap();
|
|
628
|
+
this.nextFontIdentityId = 1;
|
|
612
629
|
}
|
|
613
630
|
init() {
|
|
614
631
|
this.renderSystem = this.game.getSystem(pluginRenderer.RendererSystem);
|
|
615
632
|
this.renderSystem.rendererManager.register(this);
|
|
616
633
|
}
|
|
634
|
+
shouldFlushPresentationAddition(changed) {
|
|
635
|
+
return changed.componentName === 'Text' || changed.componentName === 'HTMLText' || changed.componentName === 'BitmapText';
|
|
636
|
+
}
|
|
617
637
|
componentChanged(changed) {
|
|
638
|
+
var _a, _b, _c, _d, _e;
|
|
618
639
|
return __awaiter(this, void 0, void 0, function* () {
|
|
640
|
+
if (this.retired)
|
|
641
|
+
return;
|
|
619
642
|
const isText = changed.componentName === 'Text';
|
|
620
643
|
const isHTMLText = changed.componentName === 'HTMLText';
|
|
621
644
|
const isBitmapText = changed.componentName === 'BitmapText';
|
|
622
645
|
if (!isText && !isHTMLText && !isBitmapText)
|
|
623
646
|
return;
|
|
647
|
+
const gameObjectId = changed.gameObject.id;
|
|
624
648
|
if (changed.type === eva_js.OBSERVER_TYPE.ADD) {
|
|
625
649
|
if (isText) {
|
|
626
|
-
|
|
650
|
+
const loading = this.addTextComponent(changed);
|
|
651
|
+
if (loading)
|
|
652
|
+
yield loading;
|
|
627
653
|
}
|
|
628
654
|
else if (isHTMLText) {
|
|
629
|
-
|
|
655
|
+
const loading = this.addHTMLTextComponent(changed);
|
|
656
|
+
if (loading)
|
|
657
|
+
yield loading;
|
|
630
658
|
}
|
|
631
659
|
else {
|
|
632
|
-
|
|
660
|
+
const loading = this.addBitmapTextComponent(changed);
|
|
661
|
+
if (loading)
|
|
662
|
+
yield loading;
|
|
663
|
+
}
|
|
664
|
+
if (((_a = this.texts[gameObjectId]) === null || _a === void 0 ? void 0 : _a.component) === changed.component) {
|
|
665
|
+
this.setSize(changed);
|
|
633
666
|
}
|
|
634
|
-
this.setSize(changed);
|
|
635
667
|
}
|
|
636
668
|
else if (changed.type === eva_js.OBSERVER_TYPE.REMOVE) {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
669
|
+
if (((_b = this.texts[gameObjectId]) === null || _b === void 0 ? void 0 : _b.component) !== changed.component && this.pendingHTMLTextComponents[gameObjectId] !== changed.component)
|
|
670
|
+
return;
|
|
671
|
+
this.increaseAsyncId(gameObjectId);
|
|
672
|
+
if (this.pendingHTMLTextComponents[gameObjectId] === changed.component) {
|
|
673
|
+
delete this.pendingHTMLTextComponents[gameObjectId];
|
|
674
|
+
}
|
|
675
|
+
const current = this.texts[gameObjectId];
|
|
676
|
+
if (!current || current.component !== changed.component)
|
|
677
|
+
return;
|
|
678
|
+
this.containerManager.getContainer(gameObjectId).removeChild(current.text);
|
|
679
|
+
current.text.destroy({ children: true });
|
|
680
|
+
delete this.texts[gameObjectId];
|
|
640
681
|
}
|
|
641
682
|
else {
|
|
642
|
-
|
|
643
|
-
// 如果样式改变且涉及字体,也需要等待字体资源加载
|
|
683
|
+
// Only a font-family replacement can introduce a new async font asset.
|
|
644
684
|
const component = changed.component;
|
|
645
|
-
|
|
646
|
-
|
|
685
|
+
const propPath = changed.prop.prop;
|
|
686
|
+
const fontFamilyChanged = propPath[0] === 'style' && (propPath.length === 1 || propPath[1] === 'fontFamily');
|
|
687
|
+
const current = this.texts[gameObjectId];
|
|
688
|
+
// A registered-font HTMLText ADD is intentionally not mounted until the
|
|
689
|
+
// font is ready. While it is pending, ordinary updates are already held
|
|
690
|
+
// by the component; a font-family change restarts (or completes) ADD.
|
|
691
|
+
if (!current) {
|
|
692
|
+
if (isHTMLText &&
|
|
693
|
+
this.pendingHTMLTextComponents[gameObjectId] === component &&
|
|
694
|
+
fontFamilyChanged) {
|
|
695
|
+
yield this.addHTMLTextComponent(changed);
|
|
696
|
+
if (((_c = this.texts[gameObjectId]) === null || _c === void 0 ? void 0 : _c.component) === component) {
|
|
697
|
+
this.setSize(changed);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
return;
|
|
701
|
+
}
|
|
702
|
+
if (current.component !== component)
|
|
703
|
+
return;
|
|
704
|
+
const waitsForFontResource = fontFamilyChanged && component.style && this.needsFontLoad(component.style.fontFamily);
|
|
705
|
+
if (fontFamilyChanged && !waitsForFontResource) {
|
|
706
|
+
// A system/CSS font switch is synchronous, but it must still cancel an
|
|
707
|
+
// older registered-font request for the same GameObject.
|
|
708
|
+
this.increaseAsyncId(gameObjectId);
|
|
709
|
+
}
|
|
710
|
+
this.change(changed);
|
|
711
|
+
if (waitsForFontResource) {
|
|
712
|
+
const { text } = current;
|
|
647
713
|
yield this.waitForFontResource(text, changed, component.style.fontFamily);
|
|
648
714
|
}
|
|
649
|
-
this.
|
|
715
|
+
if (((_d = this.texts[gameObjectId]) === null || _d === void 0 ? void 0 : _d.text) === current.text && ((_e = this.texts[gameObjectId]) === null || _e === void 0 ? void 0 : _e.component) === component) {
|
|
716
|
+
this.setSize(changed);
|
|
717
|
+
}
|
|
650
718
|
}
|
|
651
719
|
});
|
|
652
720
|
}
|
|
653
721
|
addTextComponent(changed) {
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
722
|
+
const component = changed.component;
|
|
723
|
+
// Registered Eva font assets must load before the first glyph. Ordinary
|
|
724
|
+
// CSS/system families are already valid Pixi styles and render directly.
|
|
725
|
+
const styleWithoutFont = this.processStyle(component.style);
|
|
726
|
+
const fontFamily = styleWithoutFont.fontFamily;
|
|
727
|
+
const waitsForFontResource = this.needsFontLoad(fontFamily);
|
|
728
|
+
if (waitsForFontResource)
|
|
659
729
|
delete styleWithoutFont.fontFamily;
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
}
|
|
730
|
+
const initialText = waitsForFontResource ? '' : component.text;
|
|
731
|
+
const text = new rendererAdapter.Text(initialText, styleWithoutFont);
|
|
732
|
+
this.containerManager.getContainer(changed.gameObject.id).addChildAt(text, 0);
|
|
733
|
+
this.texts[changed.gameObject.id] = {
|
|
734
|
+
text,
|
|
735
|
+
component,
|
|
736
|
+
awaitingInitialFont: waitsForFontResource,
|
|
737
|
+
};
|
|
738
|
+
// 如果指定了字体资源,等待资源加载完成后设置 fontFamily
|
|
739
|
+
if (waitsForFontResource) {
|
|
740
|
+
return this.waitForFontResource(text, changed, fontFamily);
|
|
741
|
+
}
|
|
672
742
|
}
|
|
673
743
|
addHTMLTextComponent(changed) {
|
|
744
|
+
const component = changed.component;
|
|
745
|
+
const gameObjectId = changed.gameObject.id;
|
|
746
|
+
const initialStyle = this.processStyle(component.style);
|
|
747
|
+
const fontFamily = initialStyle.fontFamily;
|
|
748
|
+
const waitsForFontResource = this.needsFontLoad(fontFamily);
|
|
749
|
+
if (waitsForFontResource) {
|
|
750
|
+
this.pendingHTMLTextComponents[gameObjectId] = component;
|
|
751
|
+
return this.addHTMLTextAfterFont(changed, component, fontFamily, this.increaseAsyncId(gameObjectId));
|
|
752
|
+
}
|
|
753
|
+
else if (this.pendingHTMLTextComponents[gameObjectId] === component) {
|
|
754
|
+
delete this.pendingHTMLTextComponents[gameObjectId];
|
|
755
|
+
}
|
|
756
|
+
this.mountHTMLText(changed, component);
|
|
757
|
+
}
|
|
758
|
+
addHTMLTextAfterFont(changed, component, fontFamily, asyncId) {
|
|
759
|
+
var _a;
|
|
674
760
|
return __awaiter(this, void 0, void 0, function* () {
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
const
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
this.
|
|
684
|
-
text: htmlText,
|
|
685
|
-
component,
|
|
686
|
-
};
|
|
687
|
-
// 如果指定了字体资源,等待资源加载完成后设置 fontFamily
|
|
688
|
-
if (fontFamily) {
|
|
689
|
-
yield this.waitForFontResource(htmlText, changed, fontFamily);
|
|
690
|
-
}
|
|
761
|
+
const gameObjectId = changed.gameObject.id;
|
|
762
|
+
const fontName = this.getFontName(fontFamily);
|
|
763
|
+
const loaded = yield this.loadFontResource(fontFamily);
|
|
764
|
+
if (!loaded || this.retired || changed.gameObject.destroyed ||
|
|
765
|
+
!this.validateAsyncId(gameObjectId, asyncId) ||
|
|
766
|
+
this.pendingHTMLTextComponents[gameObjectId] !== component ||
|
|
767
|
+
this.getFontName((_a = component.style) === null || _a === void 0 ? void 0 : _a.fontFamily) !== fontName)
|
|
768
|
+
return;
|
|
769
|
+
this.mountHTMLText(changed, component);
|
|
691
770
|
});
|
|
692
771
|
}
|
|
772
|
+
mountHTMLText(changed, component) {
|
|
773
|
+
const gameObjectId = changed.gameObject.id;
|
|
774
|
+
const style = this.processStyle(component.style);
|
|
775
|
+
const _a = component.textureStyle || {}, sampling = __rest(_a, ["resolution"]);
|
|
776
|
+
const htmlText = new rendererAdapter.HTMLText({ text: component.text, style, textureStyle: Object.assign({}, sampling) });
|
|
777
|
+
htmlText.rasterCacheFontIdentity = (families) => this.getHTMLRasterFontIdentity(families);
|
|
778
|
+
this.applyHTMLResolution(htmlText, component, changed);
|
|
779
|
+
this.containerManager.getContainer(gameObjectId).addChildAt(htmlText, 0);
|
|
780
|
+
this.texts[gameObjectId] = {
|
|
781
|
+
text: htmlText,
|
|
782
|
+
component,
|
|
783
|
+
};
|
|
784
|
+
delete this.pendingHTMLTextComponents[gameObjectId];
|
|
785
|
+
}
|
|
786
|
+
getHTMLRasterFontIdentity(families) {
|
|
787
|
+
var _a;
|
|
788
|
+
const uniqueFamilies = [...new Set(families.filter((family) => typeof family === 'string')
|
|
789
|
+
.map(family => family.replace(/["']/g, '').trim()).filter(Boolean))];
|
|
790
|
+
if (!uniqueFamilies.length)
|
|
791
|
+
return 'external:<default>';
|
|
792
|
+
const describe = (face) => [
|
|
793
|
+
this.objectIdentity(face), face.family, face.style, face.weight, face.stretch,
|
|
794
|
+
face.unicodeRange, face.variant, face.featureSettings, face.display,
|
|
795
|
+
].map(value => String(value !== null && value !== void 0 ? value : '')).join(':');
|
|
796
|
+
const identities = [];
|
|
797
|
+
for (const family of uniqueFamilies) {
|
|
798
|
+
const current = eva_js.resource.resourcesMap[family];
|
|
799
|
+
if (!current || current.type !== eva_js.RESOURCE_TYPE.FONT) {
|
|
800
|
+
identities.push(`external:${family}`);
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
if (current.complete !== true)
|
|
804
|
+
return null;
|
|
805
|
+
const rawFaces = (_a = current.data) === null || _a === void 0 ? void 0 : _a.font;
|
|
806
|
+
const faces = Array.isArray(rawFaces) ? rawFaces : [rawFaces];
|
|
807
|
+
if (!faces.length || faces.some(face => !face || typeof face !== 'object' || face.status !== 'loaded'))
|
|
808
|
+
return null;
|
|
809
|
+
identities.push(`${family}|resource:${this.objectIdentity(current)}|faces:${faces.map(describe).join(',')}`);
|
|
810
|
+
}
|
|
811
|
+
return identities.join(';');
|
|
812
|
+
}
|
|
813
|
+
objectIdentity(value) {
|
|
814
|
+
let id = this.fontIdentityIds.get(value);
|
|
815
|
+
if (!id) {
|
|
816
|
+
id = this.nextFontIdentityId++;
|
|
817
|
+
this.fontIdentityIds.set(value, id);
|
|
818
|
+
}
|
|
819
|
+
return id;
|
|
820
|
+
}
|
|
693
821
|
addBitmapTextComponent(changed) {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
822
|
+
const component = changed.component;
|
|
823
|
+
// 创建样式副本,先不设置 fontFamily
|
|
824
|
+
const styleWithoutFont = this.processStyle(component.style);
|
|
825
|
+
const fontFamily = styleWithoutFont.fontFamily;
|
|
826
|
+
const waitsForFontResource = this.needsFontLoad(fontFamily);
|
|
827
|
+
if (waitsForFontResource)
|
|
699
828
|
delete styleWithoutFont.fontFamily;
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
829
|
+
const initialText = waitsForFontResource ? '' : component.text;
|
|
830
|
+
const bitmapText = new rendererAdapter.BitmapText(initialText, styleWithoutFont);
|
|
831
|
+
this.containerManager.getContainer(changed.gameObject.id).addChildAt(bitmapText, 0);
|
|
832
|
+
this.texts[changed.gameObject.id] = {
|
|
833
|
+
text: bitmapText,
|
|
834
|
+
component,
|
|
835
|
+
awaitingInitialFont: waitsForFontResource,
|
|
836
|
+
};
|
|
837
|
+
// 如果指定了字体资源,等待资源加载完成后设置 fontFamily
|
|
838
|
+
if (waitsForFontResource) {
|
|
839
|
+
return this.waitForFontResource(bitmapText, changed, fontFamily);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
hasRegisteredFont(fontFamily) {
|
|
843
|
+
var _a;
|
|
844
|
+
if (!fontFamily)
|
|
845
|
+
return false;
|
|
846
|
+
const fontName = this.getFontName(fontFamily);
|
|
847
|
+
return ((_a = eva_js.resource.resourcesMap[fontName]) === null || _a === void 0 ? void 0 : _a.type) === eva_js.RESOURCE_TYPE.FONT;
|
|
848
|
+
}
|
|
849
|
+
needsFontLoad(fontFamily) {
|
|
850
|
+
if (!this.hasRegisteredFont(fontFamily))
|
|
851
|
+
return false;
|
|
852
|
+
// Consult the current resource generation, not a name-based font cache.
|
|
853
|
+
// A completed FONT already has its face installed; yielding here would
|
|
854
|
+
// present an empty placeholder even when the application preloaded it.
|
|
855
|
+
return eva_js.resource.resourcesMap[this.getFontName(fontFamily)].complete !== true;
|
|
856
|
+
}
|
|
857
|
+
getFontName(fontFamily) {
|
|
858
|
+
if (!fontFamily)
|
|
859
|
+
return undefined;
|
|
860
|
+
return Array.isArray(fontFamily) ? fontFamily[0] : fontFamily;
|
|
861
|
+
}
|
|
862
|
+
loadFontResource(fontFamily) {
|
|
863
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
864
|
+
const fontName = this.getFontName(fontFamily);
|
|
865
|
+
if (!fontName || !this.hasRegisteredFont(fontFamily))
|
|
866
|
+
return false;
|
|
867
|
+
const expectedResource = eva_js.resource.resourcesMap[fontName];
|
|
868
|
+
try {
|
|
869
|
+
const loaded = yield eva_js.resource.getResource(fontName);
|
|
870
|
+
// Resource resolves {} on failure or cancellation. Only the completed
|
|
871
|
+
// resource generation we requested can safely replace visible glyphs.
|
|
872
|
+
return loaded === expectedResource && loaded.complete === true &&
|
|
873
|
+
eva_js.resource.resourcesMap[fontName] === expectedResource;
|
|
874
|
+
}
|
|
875
|
+
catch (error) {
|
|
876
|
+
console.warn(`字体资源 ${fontFamily} 加载失败:`, error);
|
|
877
|
+
return false;
|
|
710
878
|
}
|
|
711
879
|
});
|
|
712
880
|
}
|
|
@@ -714,42 +882,66 @@ let Text = class Text extends pluginRenderer.Renderer {
|
|
|
714
882
|
* 等待字体资源加载完成并更新文本
|
|
715
883
|
*/
|
|
716
884
|
waitForFontResource(text, changed, fontFamily) {
|
|
885
|
+
var _a;
|
|
717
886
|
return __awaiter(this, void 0, void 0, function* () {
|
|
718
887
|
if (!fontFamily) {
|
|
719
888
|
return;
|
|
720
889
|
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
text
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
}
|
|
735
|
-
catch (error) {
|
|
736
|
-
console.warn(`字体资源 ${fontFamily} 加载失败:`, error);
|
|
890
|
+
const gameObjectId = changed.gameObject.id;
|
|
891
|
+
const fontName = this.getFontName(fontFamily);
|
|
892
|
+
if (!fontName || !this.hasRegisteredFont(fontFamily))
|
|
893
|
+
return;
|
|
894
|
+
const asyncId = this.increaseAsyncId(gameObjectId);
|
|
895
|
+
const loaded = yield this.loadFontResource(fontFamily);
|
|
896
|
+
const current = this.texts[gameObjectId];
|
|
897
|
+
if (!loaded || this.retired || changed.gameObject.destroyed ||
|
|
898
|
+
!this.validateAsyncId(gameObjectId, asyncId) ||
|
|
899
|
+
!current ||
|
|
900
|
+
current.text !== text ||
|
|
901
|
+
current.component !== changed.component) {
|
|
902
|
+
return;
|
|
737
903
|
}
|
|
904
|
+
const currentFontFamily = (_a = current.component.style) === null || _a === void 0 ? void 0 : _a.fontFamily;
|
|
905
|
+
if (this.getFontName(currentFontFamily) !== fontName)
|
|
906
|
+
return;
|
|
907
|
+
// 字体资源加载成功后,设置 fontFamily 并重新设置文本内容以触发重新渲染
|
|
908
|
+
text.style.fontFamily = currentFontFamily;
|
|
909
|
+
current.awaitingInitialFont = false;
|
|
910
|
+
text.text = current.component.text;
|
|
738
911
|
});
|
|
739
912
|
}
|
|
740
913
|
/**
|
|
741
914
|
* 将 Eva.js 的样式格式转换为 PixiJS v8 格式
|
|
742
915
|
*/
|
|
743
916
|
processStyle(style) {
|
|
744
|
-
const processed =
|
|
745
|
-
// stroke
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
width
|
|
751
|
-
};
|
|
752
|
-
|
|
917
|
+
const processed = this.cloneStyleValue(style);
|
|
918
|
+
// Preserve native v8 stroke options when merging v7 aliases. Zero is an
|
|
919
|
+
// intentional width update, not an absent value.
|
|
920
|
+
if (processed.strokeThickness != null || processed.lineJoin != null || processed.miterLimit != null) {
|
|
921
|
+
const stroke = processed.stroke;
|
|
922
|
+
const isOptions = stroke && typeof stroke === 'object' &&
|
|
923
|
+
['color', 'width', 'fill', 'texture', 'join'].some(key => key in stroke);
|
|
924
|
+
const merged = isOptions ? Object.assign({}, stroke) : { color: stroke !== null && stroke !== void 0 ? stroke : 0x000000 };
|
|
925
|
+
if (processed.strokeThickness != null)
|
|
926
|
+
merged.width = processed.strokeThickness;
|
|
927
|
+
if (processed.lineJoin != null)
|
|
928
|
+
merged.join = processed.lineJoin;
|
|
929
|
+
if (processed.miterLimit != null)
|
|
930
|
+
merged.miterLimit = processed.miterLimit;
|
|
931
|
+
// Join-only defaults must not enable a previously disabled stroke.
|
|
932
|
+
if (stroke != null || processed.strokeThickness != null)
|
|
933
|
+
processed.stroke = merged;
|
|
934
|
+
}
|
|
935
|
+
delete processed.strokeThickness;
|
|
936
|
+
delete processed.lineJoin;
|
|
937
|
+
delete processed.miterLimit;
|
|
938
|
+
// Eva exposes an enabled switch; Pixi treats every shadow object as enabled.
|
|
939
|
+
// Normalize only the cloned style so toggling back preserves configuration.
|
|
940
|
+
if (processed.dropShadow && typeof processed.dropShadow === 'object' && !Array.isArray(processed.dropShadow)) {
|
|
941
|
+
if (processed.dropShadow.enabled === false)
|
|
942
|
+
processed.dropShadow = false;
|
|
943
|
+
else
|
|
944
|
+
delete processed.dropShadow.enabled;
|
|
753
945
|
}
|
|
754
946
|
// dropShadow*(v7 平铺 alias) -> dropShadow: { color, distance, angle, alpha, blur }
|
|
755
947
|
// 关键:只有当存在任何 v7 平铺 alias 时才合并;否则保留 v8 嵌套对象(以及
|
|
@@ -785,67 +977,129 @@ let Text = class Text extends pluginRenderer.Renderer {
|
|
|
785
977
|
delete processed.dropShadowAngle;
|
|
786
978
|
delete processed.dropShadowAlpha;
|
|
787
979
|
delete processed.dropShadowBlur;
|
|
788
|
-
// fill
|
|
980
|
+
// Legacy fill is the color array; fillGradientStops contains offsets.
|
|
981
|
+
// Local coordinates keep the direction valid for any font size or bounds.
|
|
789
982
|
if (Array.isArray(processed.fill)) {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
983
|
+
const colors = processed.fill;
|
|
984
|
+
if (colors.length > 1) {
|
|
985
|
+
const supplied = processed.fillGradientStops;
|
|
986
|
+
const stops = Array.isArray(supplied) && supplied.length === colors.length
|
|
987
|
+
? supplied : colors.map((_, index) => index / (colors.length - 1));
|
|
988
|
+
const horizontal = processed.fillGradientType === 1;
|
|
989
|
+
const gradient = new pixi_js.FillGradient({
|
|
990
|
+
start: { x: 0, y: 0 },
|
|
991
|
+
end: horizontal ? { x: 1, y: 0 } : { x: 0, y: 1 },
|
|
992
|
+
textureSpace: 'local',
|
|
993
|
+
});
|
|
994
|
+
colors.forEach((color, index) => {
|
|
995
|
+
gradient.addColorStop(stops[index], pixi_js.Color.shared.setValue(color).toNumber());
|
|
996
|
+
});
|
|
997
|
+
processed.fill = { fill: gradient };
|
|
800
998
|
}
|
|
801
999
|
else {
|
|
802
|
-
|
|
1000
|
+
processed.fill = colors[0];
|
|
803
1001
|
}
|
|
804
|
-
const gradientFill = new pixi_js.FillGradient(0, 0, 0, fontSize * 1.7);
|
|
805
|
-
const fills = processed.fillGradientStops.map((color) => pixi_js.Color.shared.setValue(color).toNumber());
|
|
806
|
-
fills.forEach((number, index) => {
|
|
807
|
-
const ratio = index / (fills.length - 1);
|
|
808
|
-
gradientFill.addColorStop(ratio, number);
|
|
809
|
-
});
|
|
810
|
-
processed.fill = { fill: gradientFill };
|
|
811
|
-
delete processed.fillGradientStops;
|
|
812
1002
|
}
|
|
1003
|
+
delete processed.fillGradientStops;
|
|
1004
|
+
delete processed.fillGradientType;
|
|
813
1005
|
return processed;
|
|
814
1006
|
}
|
|
815
1007
|
change(changed) {
|
|
816
|
-
|
|
1008
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1009
|
+
const current = this.texts[changed.gameObject.id];
|
|
1010
|
+
const { text, component } = current;
|
|
817
1011
|
const isHTMLText = changed.componentName === 'HTMLText';
|
|
818
1012
|
if (changed.prop.prop[0] === 'text') {
|
|
819
|
-
|
|
1013
|
+
// First glyphs must not leak through the temporary default font while
|
|
1014
|
+
// the registered font is loading. Already-visible text can still update.
|
|
1015
|
+
if (!current.awaitingInitialFont)
|
|
1016
|
+
text.text = component.text;
|
|
820
1017
|
}
|
|
821
1018
|
else if (changed.prop.prop[0] === 'style') {
|
|
822
1019
|
const processedStyle = this.processStyle(component.style);
|
|
1020
|
+
if (this.needsFontLoad(processedStyle.fontFamily))
|
|
1021
|
+
delete processedStyle.fontFamily;
|
|
823
1022
|
Object.assign(text.style, processedStyle);
|
|
1023
|
+
if (current.awaitingInitialFont && !this.needsFontLoad((_a = component.style) === null || _a === void 0 ? void 0 : _a.fontFamily)) {
|
|
1024
|
+
current.awaitingInitialFont = false;
|
|
1025
|
+
text.text = component.text;
|
|
1026
|
+
}
|
|
824
1027
|
}
|
|
825
1028
|
else if (changed.prop.prop[0] === 'textureStyle' && isHTMLText) {
|
|
826
|
-
// HTMLText
|
|
1029
|
+
// Sampling updates do not require destroying a visible HTMLText. Passing
|
|
1030
|
+
// its observed component.style back to Pixi also allowed legacy style
|
|
1031
|
+
// conversion to re-enter Eva's observer with a nested color object.
|
|
827
1032
|
const htmlComponent = component;
|
|
828
|
-
const
|
|
829
|
-
const
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
1033
|
+
const htmlText = text;
|
|
1034
|
+
const _j = htmlComponent.textureStyle || {}, sampling = __rest(_j, ["resolution"]);
|
|
1035
|
+
if (htmlText.textureStyle) {
|
|
1036
|
+
const options = Object.assign(Object.assign({}, ((pixi_js.TextureStyle === null || pixi_js.TextureStyle === void 0 ? void 0 : pixi_js.TextureStyle.defaultOptions) || { addressMode: 'clamp-to-edge', scaleMode: 'linear' })), sampling);
|
|
1037
|
+
htmlText.textureStyle.addressMode = options.addressMode;
|
|
1038
|
+
htmlText.textureStyle.scaleMode = options.scaleMode;
|
|
1039
|
+
Object.assign(htmlText.textureStyle, {
|
|
1040
|
+
addressModeU: (_b = options.addressModeU) !== null && _b !== void 0 ? _b : options.addressMode,
|
|
1041
|
+
addressModeV: (_c = options.addressModeV) !== null && _c !== void 0 ? _c : options.addressMode,
|
|
1042
|
+
addressModeW: (_d = options.addressModeW) !== null && _d !== void 0 ? _d : options.addressMode,
|
|
1043
|
+
magFilter: (_e = options.magFilter) !== null && _e !== void 0 ? _e : options.scaleMode,
|
|
1044
|
+
minFilter: (_f = options.minFilter) !== null && _f !== void 0 ? _f : options.scaleMode,
|
|
1045
|
+
mipmapFilter: (_g = options.mipmapFilter) !== null && _g !== void 0 ? _g : options.scaleMode,
|
|
1046
|
+
lodMinClamp: options.lodMinClamp, lodMaxClamp: options.lodMaxClamp,
|
|
1047
|
+
compare: options.compare, maxAnisotropy: (_h = options.maxAnisotropy) !== null && _h !== void 0 ? _h : 1,
|
|
1048
|
+
});
|
|
1049
|
+
htmlText.textureStyle.update();
|
|
1050
|
+
}
|
|
1051
|
+
else {
|
|
1052
|
+
htmlText.textureStyle = new pixi_js.TextureStyle(sampling);
|
|
1053
|
+
}
|
|
1054
|
+
this.applyHTMLResolution(htmlText, htmlComponent, changed);
|
|
839
1055
|
}
|
|
840
1056
|
}
|
|
1057
|
+
applyHTMLResolution(text, component, changed) {
|
|
1058
|
+
var _a, _b, _c, _d;
|
|
1059
|
+
// Render's explicit resolution remains authoritative, including when HTML
|
|
1060
|
+
// mounts after an asynchronous font load and misses Render's ADD callback.
|
|
1061
|
+
const render = (_b = (_a = changed.gameObject).getComponent) === null || _b === void 0 ? void 0 : _b.call(_a, 'Render');
|
|
1062
|
+
const resolution = (_c = render === null || render === void 0 ? void 0 : render.resolution) !== null && _c !== void 0 ? _c : (_d = component.textureStyle) === null || _d === void 0 ? void 0 : _d.resolution;
|
|
1063
|
+
if (typeof resolution === 'number' && Number.isFinite(resolution) && resolution > 0 && text.resolution !== resolution) {
|
|
1064
|
+
text.resolution = resolution;
|
|
1065
|
+
}
|
|
1066
|
+
else if (resolution == null) {
|
|
1067
|
+
text.resolution = null;
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
onDestroy() {
|
|
1071
|
+
var _a, _b;
|
|
1072
|
+
this.retired = true;
|
|
1073
|
+
for (const id of Object.keys(this.asyncIdMap))
|
|
1074
|
+
this.increaseAsyncId(Number(id));
|
|
1075
|
+
this.pendingHTMLTextComponents = {};
|
|
1076
|
+
for (const { text } of Object.values(this.texts)) {
|
|
1077
|
+
(_a = text.parent) === null || _a === void 0 ? void 0 : _a.removeChild(text);
|
|
1078
|
+
if (!text.destroyed)
|
|
1079
|
+
(_b = text.destroy) === null || _b === void 0 ? void 0 : _b.call(text, { children: true });
|
|
1080
|
+
}
|
|
1081
|
+
this.texts = {};
|
|
1082
|
+
}
|
|
1083
|
+
cloneStyleValue(value) {
|
|
1084
|
+
if (Array.isArray(value))
|
|
1085
|
+
return value.map(item => this.cloneStyleValue(item));
|
|
1086
|
+
if (value && Object.getPrototypeOf(value) === Object.prototype) {
|
|
1087
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, this.cloneStyleValue(child)]));
|
|
1088
|
+
}
|
|
1089
|
+
// Preserve class-based Pixi fills/gradients/textures; clone plain component data.
|
|
1090
|
+
return value;
|
|
1091
|
+
}
|
|
841
1092
|
setSize(changed) {
|
|
842
1093
|
const { transform } = changed.gameObject;
|
|
843
1094
|
if (!transform)
|
|
844
1095
|
return;
|
|
845
1096
|
const { text } = this.texts[changed.gameObject.id];
|
|
846
1097
|
const size = text.getSize();
|
|
1098
|
+
if (transform.size.width === size.width && transform.size.height === size.height)
|
|
1099
|
+
return;
|
|
847
1100
|
transform.size.width = size.width;
|
|
848
1101
|
transform.size.height = size.height;
|
|
1102
|
+
this.renderSystem.commitIntrinsicSize(changed.gameObject);
|
|
849
1103
|
}
|
|
850
1104
|
};
|
|
851
1105
|
Text.systemName = 'Text';
|