From dc2a7f6e521d56d0ea04968707a587547bf8f700 Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Sat, 30 Nov 2024 21:37:55 +0100 Subject: [PATCH 1/4] text: Fix bullet indent Apparently it should be 36px, not 35px. --- core/src/html/layout.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/html/layout.rs b/core/src/html/layout.rs index bb6ddd4d5067..73f92c074b73 100644 --- a/core/src/html/layout.rs +++ b/core/src/html/layout.rs @@ -862,9 +862,9 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> { fn left_alignment_offset(span: &TextSpan, is_first_line: bool) -> Twips { if span.bullet { if is_first_line { - Twips::from_pixels(35.0 + span.left_margin + span.block_indent + span.indent) + Twips::from_pixels(36.0 + span.left_margin + span.block_indent + span.indent) } else { - Twips::from_pixels(35.0 + span.left_margin + span.block_indent) + Twips::from_pixels(36.0 + span.left_margin + span.block_indent) } } else { Self::left_alignment_offset_without_bullet(span, is_first_line) From a8a5e16e9e94c6f106c27288241ae13992a61184 Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Sat, 30 Nov 2024 21:43:06 +0100 Subject: [PATCH 2/4] text: Do not show text that's missing an embedded font Flash Player does not show any text that requires an embedded font that is missing. --- core/src/html/layout.rs | 8 ++++---- .../embed_matching/no_font_found/test.toml | 1 - .../fonts/font_lookup_as3/output.expected.png | Bin 14543 -> 6062 bytes 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/html/layout.rs b/core/src/html/layout.rs index 73f92c074b73..e0082225c752 100644 --- a/core/src/html/layout.rs +++ b/core/src/html/layout.rs @@ -660,10 +660,10 @@ impl<'a, 'gc> LayoutContext<'a, 'gc> { { return font; } - // TODO: If set to use embedded fonts and we couldn't find any matching font, show nothing - // However - at time of writing, we don't support DefineFont4. If we matched this behaviour, - // then a bunch of SWFs would just show no text suddenly. - // return new_empty_font(context, span, self.font_type); + + // If set to use embedded fonts and we couldn't find any matching font, show nothing. + tracing::warn!("Embedded font not found: {font_name}, using an empty font"); + return new_empty_font(context, span, self.font_type); } // Check if the font name is one of the known default fonts. diff --git a/tests/tests/swfs/fonts/embed_matching/no_font_found/test.toml b/tests/tests/swfs/fonts/embed_matching/no_font_found/test.toml index 79c486db198e..1d1205f06dc8 100644 --- a/tests/tests/swfs/fonts/embed_matching/no_font_found/test.toml +++ b/tests/tests/swfs/fonts/embed_matching/no_font_found/test.toml @@ -1,7 +1,6 @@ # There are no fonts embedded in this swf. It should not render anything at all, or error. num_frames = 1 -known_failure = true # Right now we intentionally fall back, because we don't support DefineFont4 embedded fonts yet [image_comparisons.output] tolerance = 0 diff --git a/tests/tests/swfs/visual/fonts/font_lookup_as3/output.expected.png b/tests/tests/swfs/visual/fonts/font_lookup_as3/output.expected.png index eb0809b9908e61abb7075d7313d0235a961a49f3..0ffa47eb59e431961c927a2c3d0483a5a444fef5 100644 GIT binary patch literal 6062 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 literal 14543 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 N>_w}WHy3U`@V_E&Qp5lN From 17a4bc8a6c1fd06b61c430842e67af4009927779 Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Sat, 30 Nov 2024 21:03:39 +0100 Subject: [PATCH 3/4] tests: Add avm2/edittext_bullet_font test This test verifies how bullets are rendered and which font should be used. --- .../swfs/avm2/edittext_bullet_font/Test.as | 47 ++++++ .../edittext_bullet_font/TestFontBulletA.sfd | 134 +++++++++++++++++ .../edittext_bullet_font/TestFontBulletA.ttf | Bin 0 -> 1796 bytes .../edittext_bullet_font/TestFontBulletB.sfd | 139 ++++++++++++++++++ .../edittext_bullet_font/TestFontBulletB.ttf | Bin 0 -> 1796 bytes .../edittext_bullet_font/output.expected.png | Bin 0 -> 759 bytes .../swfs/avm2/edittext_bullet_font/output.txt | 0 .../swfs/avm2/edittext_bullet_font/test.swf | Bin 0 -> 2336 bytes .../swfs/avm2/edittext_bullet_font/test.toml | 7 + 9 files changed, 327 insertions(+) create mode 100644 tests/tests/swfs/avm2/edittext_bullet_font/Test.as create mode 100644 tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletA.sfd create mode 100644 tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletA.ttf create mode 100644 tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletB.sfd create mode 100644 tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletB.ttf create mode 100644 tests/tests/swfs/avm2/edittext_bullet_font/output.expected.png create mode 100644 tests/tests/swfs/avm2/edittext_bullet_font/output.txt create mode 100644 tests/tests/swfs/avm2/edittext_bullet_font/test.swf create mode 100644 tests/tests/swfs/avm2/edittext_bullet_font/test.toml diff --git a/tests/tests/swfs/avm2/edittext_bullet_font/Test.as b/tests/tests/swfs/avm2/edittext_bullet_font/Test.as new file mode 100644 index 000000000000..777837686ef7 --- /dev/null +++ b/tests/tests/swfs/avm2/edittext_bullet_font/Test.as @@ -0,0 +1,47 @@ +package { +import flash.display.Sprite; +import flash.text.TextField; +import flash.text.TextFormat; + +[SWF(width="200", height="200")] +public class Test extends Sprite { + [Embed(source="TestFontBulletA.ttf", fontName="TestFontNoBullet", embedAsCFF="false", unicodeRange="U+0061-U+0064")] + private var TestFontNoBullet:Class; + + [Embed(source="TestFontBulletA.ttf", fontName="TestFontBulletA", embedAsCFF="false", unicodeRange="U+0061-U+0064,U+2022")] + private var TestFontBulletA:Class; + + [Embed(source="TestFontBulletB.ttf", fontName="TestFontBulletB", embedAsCFF="false", unicodeRange="U+0061-U+0064,U+2022")] + private var TestFontBulletB:Class; + + public function Test() { + stage.scaleMode = "noScale"; + + newTextField(5, 5, "TestFontBulletA", "
  • a
  • "); + newTextField(5, 55, "TestFontBulletA", "
  • a
  • "); + newTextField(5, 105, "TestFontBulletA", "
  • a
  • "); + newTextField(5, 155, "TestFontBulletA", "
  • aa
  • "); + newTextField(105, 5, "TestFontBulletA", "
  • aa
  • "); + newTextField(105, 55, "TestFontBulletA", "
  • a
  • "); + newTextField(105, 105, "TestFontBulletA", "
  • aa
  • "); + newTextField(105, 155, "TestFontBulletA", "
  • aa
  • "); + } + + private function newTextField(x: int, y: int, defaultFont: String, htmlText: String):void { + var text = new TextField(); + text.border = true; + text.x = x; + text.y = y; + text.width = 90; + text.height = 40; + text.embedFonts = true; + var tf = new TextFormat(); + tf.font = defaultFont; + tf.size = 20; + tf.leading = 5; + text.defaultTextFormat = tf; + text.htmlText = htmlText; + addChild(text); + } +} +} diff --git a/tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletA.sfd b/tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletA.sfd new file mode 100644 index 000000000000..de2cf270622e --- /dev/null +++ b/tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletA.sfd @@ -0,0 +1,134 @@ +SplineFontDB: 3.2 +FontName: TestFontBulletA +FullName: TestFontBulletA +FamilyName: TestFontBulletA +Weight: Regular +Copyright: Copyright (c) 2024, Kamil Jarosz +UComments: "2024-7-24: Created with FontForge (http://fontforge.org)" +Version: 001.000 +ItalicAngle: 0 +UnderlinePosition: -76 +UnderlineWidth: 38 +Ascent: 800 +Descent: 200 +InvalidEm: 0 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 253 198287149 6396829] +StyleMap: 0x0000 +FSType: 0 +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 1 +CreationTime: 1721856925 +ModificationTime: 1732996340 +PfmFamily: 17 +TTFWeight: 400 +TTFWidth: 5 +LineGap: 100 +VLineGap: 0 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 100 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +OS2Vendor: 'PfEd' +MarkAttachClasses: 1 +DEI: 91125 +Encoding: UnicodeBmp +UnicodeInterp: none +NameList: AGL For New Fonts +DisplaySize: -48 +AntiAlias: 1 +FitToEm: 0 +WinInfo: 8190 30 10 +BeginPrivate: 0 +EndPrivate +BeginChars: 65536 5 + +StartChar: a +Encoding: 97 97 0 +Width: 800 +Flags: HW +LayerCount: 2 +Fore +SplineSet +0 800 m 5 + 800 800 l 5 + 800 0 l 1 + 0 0 l 1 + 0 800 l 5 +EndSplineSet +EndChar + +StartChar: b +Encoding: 98 98 1 +Width: 108 +VWidth: 1083 +Flags: HW +LayerCount: 2 +Fore +SplineSet +0 800 m 5 + 108 800 l 5 + 108 0 l 1 + 0 0 l 1 + 0 800 l 5 +EndSplineSet +EndChar + +StartChar: c +Encoding: 99 99 2 +Width: 800 +Flags: HW +LayerCount: 2 +Fore +SplineSet +0 0 m 1 + 800 0 l 1 + 800 -200 l 5 + 0 -200 l 5 + 0 0 l 1 +EndSplineSet +EndChar + +StartChar: d +Encoding: 100 100 3 +Width: 100 +Flags: HW +LayerCount: 2 +Fore +SplineSet +0 0 m 1 + 100 0 l 1 + 100 -200 l 5 + 0 -200 l 5 + 0 0 l 1 +EndSplineSet +EndChar + +StartChar: bullet +Encoding: 8226 8226 4 +Width: 800 +Flags: HW +LayerCount: 2 +Fore +SplineSet +100 700 m 1 + 700 700 l 1 + 700 100 l 5 + 100 100 l 5 + 100 700 l 1 +EndSplineSet +EndChar +EndChars +EndSplineFont diff --git a/tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletA.ttf b/tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletA.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1bfcf30314c9b08b14717f22ced4f5cefb14d752 GIT binary patch literal 1796 zcmbtVO=w(I6#njeZ(b%?8dA-wX}Qw|ot7kh^Cn0vv#9x*NZMkFB?b}f>%5nlDR1(| znHO!kD*hm-i&A$5HwqFElngGj6yic$6qkY_MQFwDbeAyw?w#9UEmTVHaNqgPch0%z z+;cB?AOIZ1b=bI6E?+#qUaH>&+`D9l=VoTh7{UwGe^&bIZ=CWMzZY|Ws8PREX#~yb z-9HoR^cVA$_fm#z`d*!}y!=lhhA2f~!rO!z;AErtB+0BWfQ0 z(qU=|Sj}eAPH_i6F#iqOeW<;1rf+WFerKTc51zAGH?Xrcazx2H?;c5k?xZbkNi_>g zu^f!CWp@&x=85%6JzMXa)l7CjMnwwEox!+vajbrE0~yx!skKSw^PUvjCvmwbq9^0=$bwlk1Tu}`PA!6hd6z5f~1hJ8!mi(%7&~vyKiy3Nam0>u@ zQ@WIbg@p1LPYo(#x7+>d_dkq3DdBQbs-dc;_oL&X@lp2aG~3BA&9jZZXAA$IXnn_V zQvW8|#|wBHR~TcdGY}`OTkLEf#y12`l{$S6?)w{V=C@MEwg|CdD>|d-PM<4wOC7fI zzF!>74Zc(yJf0K%cel2zTYJknYss`*-$K4<3 zd?7caV|Zya4|5j^#i8S2sIC(E5TUindrAN2nIp88_SUV(?hi0@1$Kw`>ZfdPDI zu*KbeZLp0|kuli8fLJg%L;QikE^&vsgwxOU&v5pzz)@5TwwU(|gKaF~TZ0`O6~4h4 z;>!lR#5XaG1Wl}=g*vLJA!WsRu6csehsQaAQR1@*(4bFDJWt$WTpQPb>7=>Vs#j~N z%vVlG-}5I%<=LQ7kL7&OO4{_eh={H!$_!bdoWd%XiOHsTmFB3OmXnoqYBi3dl*9rp zRqdnFU?Hlm#sR^@cqLo(h**lx$HJpL&H3a!J)a`I$57yJY=3)D*~>|*8cBcLlc(i> zDk4+##tMZowYjI?&LRtKu>p0xeaQkmrdMUF9~PrlyPm8_&nt|39*HM!SJLtd>V%GMeHhTO9 literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletB.sfd b/tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletB.sfd new file mode 100644 index 000000000000..58c8a5ae72c6 --- /dev/null +++ b/tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletB.sfd @@ -0,0 +1,139 @@ +SplineFontDB: 3.2 +FontName: TestFontBulletB +FullName: TestFontBulletB +FamilyName: TestFontBulletB +Weight: Regular +Copyright: Copyright (c) 2024, Kamil Jarosz +UComments: "2024-7-24: Created with FontForge (http://fontforge.org)" +Version: 001.000 +ItalicAngle: 0 +UnderlinePosition: -76 +UnderlineWidth: 38 +Ascent: 800 +Descent: 200 +InvalidEm: 0 +LayerCount: 2 +Layer: 0 0 "Back" 1 +Layer: 1 0 "Fore" 0 +XUID: [1021 253 198287149 6396829] +StyleMap: 0x0000 +FSType: 0 +OS2Version: 0 +OS2_WeightWidthSlopeOnly: 0 +OS2_UseTypoMetrics: 1 +CreationTime: 1721856925 +ModificationTime: 1732996414 +PfmFamily: 17 +TTFWeight: 400 +TTFWidth: 5 +LineGap: 100 +VLineGap: 0 +OS2TypoAscent: 0 +OS2TypoAOffset: 1 +OS2TypoDescent: 0 +OS2TypoDOffset: 1 +OS2TypoLinegap: 100 +OS2WinAscent: 0 +OS2WinAOffset: 1 +OS2WinDescent: 0 +OS2WinDOffset: 1 +HheadAscent: 0 +HheadAOffset: 1 +HheadDescent: 0 +HheadDOffset: 1 +OS2Vendor: 'PfEd' +MarkAttachClasses: 1 +DEI: 91125 +Encoding: UnicodeBmp +UnicodeInterp: none +NameList: AGL For New Fonts +DisplaySize: -48 +AntiAlias: 1 +FitToEm: 0 +WinInfo: 8190 30 10 +BeginPrivate: 0 +EndPrivate +BeginChars: 65536 5 + +StartChar: a +Encoding: 97 97 0 +Width: 800 +Flags: HW +LayerCount: 2 +Fore +SplineSet +0 800 m 5 + 800 800 l 5 + 800 0 l 1 + 0 0 l 1 + 0 800 l 5 +EndSplineSet +Validated: 1 +EndChar + +StartChar: b +Encoding: 98 98 1 +Width: 108 +VWidth: 1083 +Flags: HW +LayerCount: 2 +Fore +SplineSet +0 800 m 5 + 108 800 l 5 + 108 0 l 1 + 0 0 l 1 + 0 800 l 5 +EndSplineSet +Validated: 1 +EndChar + +StartChar: c +Encoding: 99 99 2 +Width: 800 +Flags: HW +LayerCount: 2 +Fore +SplineSet +0 0 m 1 + 800 0 l 1 + 800 -200 l 5 + 0 -200 l 5 + 0 0 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: d +Encoding: 100 100 3 +Width: 100 +Flags: HW +LayerCount: 2 +Fore +SplineSet +0 0 m 1 + 100 0 l 1 + 100 -200 l 5 + 0 -200 l 5 + 0 0 l 1 +EndSplineSet +Validated: 1 +EndChar + +StartChar: bullet +Encoding: 8226 8226 4 +Width: 800 +Flags: HW +LayerCount: 2 +Fore +SplineSet +300 500 m 1 + 500 500 l 5 + 500 300 l 5 + 300 300 l 1 + 300 500 l 1 +EndSplineSet +Validated: 1 +EndChar +EndChars +EndSplineFont diff --git a/tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletB.ttf b/tests/tests/swfs/avm2/edittext_bullet_font/TestFontBulletB.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c7b20dfe7cafb54f61460f1fe95bf6fde886a3a6 GIT binary patch literal 1796 zcmbtVPiP!v6#soQvy%-LLy7?pY52AcnwHIWb~Z>Xdnoy{k+j7ULntWNad)!2GMia< zC$;fZ6j8)O(OYjSh#;t0^j16x$-$$?f~7^M(%#}hh^)W&?KId5mC|qc_Wj=Pz4yKM zy?M++0eBi$VB=z?vU={Ta`Oh@-XS}_w6Ivg7@nd2v*<6sa?)S>RxJUlLH%O26}0E~ z|A?v6UoBTJB^o(v3$SNscj`g6-S6{cxIa>EKVY)^ca zVQLLn?RMNva2ww<|5e(3$X&TF{qXAb*GI~K;whVT1Gjc2kBGee){!59{;aKSO*IQk zST4rcx<8AW;fc*j1KZ#?Ynbdoj6^EKokqd9IM%Sb3f5+QWL+oo@j$AZC@Oke$goec zu9$oVnxFIQi#3vgK6+4tbVKd}o+wL0sR%iN(k)YEl**b&m8VJ0mpwj+#R4@sWgHHs zC|yd$LTdUb-x?%izu*7-*WXfqQp)9~lqFTu`@wbJ_#pdun(btm=E>I3lZF3Jw3%_7 zFwZRecpk6eO~zRA4%7+j8aq3L!nVT6a&O4NJ%8KH+$i^KixAtk&>5k7L$2B{_t?sN zerYr}`h02hSWXS!+1atK{k@*EE~M=?6Ulc+mz=HlZ^~xALAN8mZ?Q2pBBq7BOffyk z7jt7KhC^d`a3Ty}8ar02$tZDp@_hExp74si%J1%~J!6xv!#4*nU1KiA3L|(g#TIY- zMT%|YRVKv_M$}4*GsN$v*d^{UmvV-g{WSLgD@>r8VvBh{O|gv&_&UW7CX}Dz4DlN& zc8Nd1JYux5g$|miqk#mPvt7k;N*^Bg4D!Th5THe$hG9slhkyx zuoBicqk!OkyvPncLQ`UaMQWVlesrFJPl?{sDDs&;xE>^XCGONi?H4?KNf(bxEIyDUxvSAPf34bVfs rS?cnYTEHS(xP%XkUGa-$rPBo*;(wMyUd~eK9w6LurcA)Uzxn?FyBhll literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/edittext_bullet_font/output.expected.png b/tests/tests/swfs/avm2/edittext_bullet_font/output.expected.png new file mode 100644 index 0000000000000000000000000000000000000000..e4b7f68b10f127dfc6e1c7968fc11fef49219d48 GIT binary patch literal 759 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST~P>foY$oi(^Q|t+#i*iw-M@xE}QG z`n&1BU}S^shBrd?rToTcE^~@?xxU={ogx44PtgVk2L%NIi52^PCu$zePn+QX&Erh+ zJ)2kh&5zB)^=dxPFz&B<#rjk!x?WB>EdINK!7sU#srxPdJ(}(QCaDpuS%5=9K!AgT zg@uWUvC-j=e%K#<|FZvjU7{=z$*dp6&vT`)GB$$jsbfV_2(cJsIb3gpg93lu>dwtO z-(Qb9t*3sn@;9jriuA?iVDA9+^UY(1Nlo-^b4p30E+t7nRz9y0H@{Jdg$ zT!5a@=K_9^J3z_>o-cXc7b~#ar?WD`5oA*V|D=`w+gqSKkXbig|5hlAJad=}rbj^l z%}EXl2%A}$ZvI%ScJA4}_-x(9ep87}WC+l^yCYKVC8Gp1Uzo?(?%i z*)ZetQ@QWkJUg>^UX|m{6W8V+=Tnc_$qw^TNAacjGRHSYiQqswVC!L4FT@oF3zWti zN4sLz|M)gnl%?hf6F7vCor7X8Bpjbi-agA>_V2p2Ti+BddK3ISa98=uhW-fDV4k<+ zc<^nVvSV$PXJ)&XMx3=lifWgoU!QM0{Qj~nJWA(G{A% zBzDb>ucuz#Z`;xYavHMp!12I<6m^g!vgfMGxo2|Aw@!=o`%(MK#_PMD><2+^pj>0& aKSr6$OW4*rGF|~DXa-MLKbLh*2~7a~qz!=p literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/edittext_bullet_font/output.txt b/tests/tests/swfs/avm2/edittext_bullet_font/output.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/tests/swfs/avm2/edittext_bullet_font/test.swf b/tests/tests/swfs/avm2/edittext_bullet_font/test.swf new file mode 100644 index 0000000000000000000000000000000000000000..5a2dfe4737e9b376f4585455ef7950a4cade98ae GIT binary patch literal 2336 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 G+vnFK^Os}* literal 0 HcmV?d00001 diff --git a/tests/tests/swfs/avm2/edittext_bullet_font/test.toml b/tests/tests/swfs/avm2/edittext_bullet_font/test.toml new file mode 100644 index 000000000000..454b7bf7f4dc --- /dev/null +++ b/tests/tests/swfs/avm2/edittext_bullet_font/test.toml @@ -0,0 +1,7 @@ +num_ticks = 1 + +[image_comparisons.output] +tolerance = 128 + +[player_options] +with_renderer = { optional = false, sample_count = 4 } From 4b6257ea25312d7e4b42b55a438b44a1d925f9d1 Mon Sep 17 00:00:00 2001 From: Kamil Jarosz Date: Sat, 30 Nov 2024 19:54:22 +0100 Subject: [PATCH 4/4] tests: Add avm2/edittext_missing_font test This test verifies how FP behaves when we want to get some metrics related to text that uses a font which is missing. --- .../swfs/avm2/edittext_missing_font/Test.as | 54 +++++++++++++++++ .../avm2/edittext_missing_font/output.txt | 56 ++++++++++++++++++ .../swfs/avm2/edittext_missing_font/test.swf | Bin 0 -> 1609 bytes .../swfs/avm2/edittext_missing_font/test.toml | 1 + 4 files changed, 111 insertions(+) create mode 100644 tests/tests/swfs/avm2/edittext_missing_font/Test.as create mode 100644 tests/tests/swfs/avm2/edittext_missing_font/output.txt create mode 100644 tests/tests/swfs/avm2/edittext_missing_font/test.swf create mode 100644 tests/tests/swfs/avm2/edittext_missing_font/test.toml diff --git a/tests/tests/swfs/avm2/edittext_missing_font/Test.as b/tests/tests/swfs/avm2/edittext_missing_font/Test.as new file mode 100644 index 000000000000..ad615072927d --- /dev/null +++ b/tests/tests/swfs/avm2/edittext_missing_font/Test.as @@ -0,0 +1,54 @@ +package { +import flash.display.Sprite; +import flash.text.TextField; +import flash.text.TextFormat; + +[SWF(width="200", height="200")] +public class Test extends Sprite { + private var nextY: int = 0; + private var nextX: int = 0; + + public function Test() { + stage.scaleMode = "noScale"; + + newTextField(true, "input"); + newTextField(true, "dynamic"); + newTextField(false, "input"); + newTextField(false, "dynamic"); + } + + private function newTextField(device: Boolean, type: String):void { + var text = new TextField(); + text.type = type; + text.border = true; + text.x = nextX; + text.y = nextY; + nextY += 42; + text.width = 100; + text.height = 40; + text.embedFonts = !device; + var tf = new TextFormat(); + tf.font = "Unknown Font 6ad5511bcd8b089c25e2212243c819d1"; + tf.size = 20; + tf.leading = 5; + text.defaultTextFormat = tf; + text.text = "xyz"; + addChild(text); + + trace("device=" + device + ", type=" + type); + trace(" getTextFormat(0, 1).font=" + (text.getTextFormat(0, 1).font)); + trace(" length=" + text.length); + trace(" text=" + text.text); + trace(" numLines=" + text.numLines); + trace(" textWidth is zero?=" + (text.textWidth == 0)); + trace(" getCharBoundaries(0) is null?=" + (text.getCharBoundaries(0) == null)); + trace(" getCharBoundaries(1) is null?=" + (text.getCharBoundaries(1) == null)); + trace(" getCharBoundaries(3) is null?=" + (text.getCharBoundaries(3) == null)); + trace(" getLineMetrics(0).ascent is zero?=" + (text.getLineMetrics(0).ascent == 0)); + trace(" getLineMetrics(0).descent is zero?=" + (text.getLineMetrics(0).descent == 0)); + trace(" getLineMetrics(0).height is 5?=" + (text.getLineMetrics(0).height == 5)); + trace(" getLineMetrics(0).leading=" + (text.getLineMetrics(0).leading)); + trace(" getLineMetrics(0).width is zero?=" + (text.getLineMetrics(0).width == 0)); + } +} +} diff --git a/tests/tests/swfs/avm2/edittext_missing_font/output.txt b/tests/tests/swfs/avm2/edittext_missing_font/output.txt new file mode 100644 index 000000000000..80b1571cb785 --- /dev/null +++ b/tests/tests/swfs/avm2/edittext_missing_font/output.txt @@ -0,0 +1,56 @@ +device=true, type=input + getTextFormat(0, 1).font=Unknown Font 6ad5511bcd8b089c25e2212243c819d1 + length=3 + text=xyz + numLines=1 + textWidth is zero?=false + getCharBoundaries(0) is null?=false + getCharBoundaries(1) is null?=false + getCharBoundaries(3) is null?=true + getLineMetrics(0).ascent is zero?=false + getLineMetrics(0).descent is zero?=false + getLineMetrics(0).height is 5?=false + getLineMetrics(0).leading=5 + getLineMetrics(0).width is zero?=false +device=true, type=dynamic + getTextFormat(0, 1).font=Unknown Font 6ad5511bcd8b089c25e2212243c819d1 + length=3 + text=xyz + numLines=1 + textWidth is zero?=false + getCharBoundaries(0) is null?=false + getCharBoundaries(1) is null?=false + getCharBoundaries(3) is null?=true + getLineMetrics(0).ascent is zero?=false + getLineMetrics(0).descent is zero?=false + getLineMetrics(0).height is 5?=false + getLineMetrics(0).leading=5 + getLineMetrics(0).width is zero?=false +device=false, type=input + getTextFormat(0, 1).font=Unknown Font 6ad5511bcd8b089c25e2212243c819d1 + length=3 + text=xyz + numLines=1 + textWidth is zero?=true + getCharBoundaries(0) is null?=true + getCharBoundaries(1) is null?=true + getCharBoundaries(3) is null?=true + getLineMetrics(0).ascent is zero?=true + getLineMetrics(0).descent is zero?=true + getLineMetrics(0).height is 5?=true + getLineMetrics(0).leading=5 + getLineMetrics(0).width is zero?=true +device=false, type=dynamic + getTextFormat(0, 1).font=Unknown Font 6ad5511bcd8b089c25e2212243c819d1 + length=3 + text=xyz + numLines=1 + textWidth is zero?=true + getCharBoundaries(0) is null?=true + getCharBoundaries(1) is null?=true + getCharBoundaries(3) is null?=true + getLineMetrics(0).ascent is zero?=true + getLineMetrics(0).descent is zero?=true + getLineMetrics(0).height is 5?=true + getLineMetrics(0).leading=5 + getLineMetrics(0).width is zero?=true diff --git a/tests/tests/swfs/avm2/edittext_missing_font/test.swf b/tests/tests/swfs/avm2/edittext_missing_font/test.swf new file mode 100644 index 0000000000000000000000000000000000000000..080ba80b17ccc6eab0ee8143e824a8cd1be39e7d GIT binary patch literal 1609 zcmV-P2DbS_S5qlh3IG6j0fkk~a@$4{o&i8YpeRbR{;5AmqD9H!4+u(*B#W|SDNO9d zc4FFbvQ;eA5EzhHLjVf^MahRGl~>rRJ?p*?v8NpN#)OA`g;Xv^p1^4Uv_vMV3aT(O z{dIpmJ?QR111%pSzJt&#MknL52%+yMe#Hpw+p4zr;-oBIoEfIG2U02BaNXu!KHqM) zbM0czvg`T6?(S}0lJl~h1&ge6X}aVhYdUM`gTTQFbrf4~y1HeGzC%*8T5c(w?s-*} zYp2bYZ3He=B~J}{Morhr7jgw~q$+!wWuFoEfHa$it`Of{{vzu%Eagp`oYSmk5T~)9 zzcKVVuI?K2;HXKI1{KQ&y%3LX=z(!);oGV=aUS$esR1KL0(KBr!05O0dCgYM(47Xg zKkQSnG`CG`*wAX3Y7l8ayfO4?icN`Y{VnN(nNKl@S#Oa#J)q|4t4iSW8VXK8Tzc@# zIv0ylMwBIaD~#7i_w)Xz?@L7wf$Scj#8_+Y+4Jm|N0rL!=PyoBXB0|c;5ixlmEA|j z%=`E6{}E$B6@`}@d-J~{lnFv>G2^>`!Rn{jOX|4jzmvc52>F^o978$8fbg0N#F0Ft z@WBIrog+@fap6R~X;lWsVDeS5RP6I2>(ceVbH4M^$bd!= zMT44kw^53QGcSsM!b-!UXtvJ2fUoM5hCZyOLgj1!)S~W)Z>eoPED1g##DaZ~8^nGT zw4SX~XG7ZbP0f~JJS>gF=7VbSHcFw7a;rhH&ma|e@FRUnU0YZD9ih||NZ?J33D~&L zBpT}P-bVHBmjNz(-2hp+%{t7zztQ%?(!y;Py+oGQZc_#YbQ9)W&{|ON=WuE4^*0}P zZs{uj$g;ql8LhxU%{r@_?#$_F-8yxxQ>YW&)ctGuv_Xv~+q4|Euv28^!Zy3LQy3X2 z{b<-!(XcH>|5WYq{#Fcte{2q_6Snn!qE>3WsO~vl#K=jM*c^V7QP0TRp*uWw{84Fdh=vj`V2& z3$erBS#P)_!TT6_@haAECPEl5(OJ*%WtQ3WMqwoctFcbHhmFH3#O{C}CK3^1S1dT1 z>`3qMFq(Xa;~0h!X6hYIuuI-lm3zXWAOG)7cYh%fZ>GCWqTXz`qw!?On}b;(F)!JH zId$)Gtt#J$Dt&;KSP-cmL3B!PZZIB&VeWmd?jC)T*sBpLHoV2+S+ zZ?#+F$Q^I3n^`9lUaC6TEl=W2Z@oH|+5Gt`bMNYxtMU{8X#hUzrcer(rx|TD1UCT8 zcD0#M+5{=z)h0se9!OGGn+>IpK$5%KTnhas1Tp|@fxmJRi#;d{(EToKa0BH4`na27 z`=C5PJ3et9YYW%zBtReZ(8X)C0BEU)##52rJ~E&OJ#;*brU=l(9yEMS--1N33?zTI zBSEHkimE9sB~|ZgcctpOwk}oET3V`ZXd6;>O