Troika: [troika-three-text] IOS Safari 加载问题

创建于 2020-11-21  ·  47评论  ·  资料来源: protectwise/troika

你好!

首先我想说这个包比过去的其他东西更容易使用。 所以非常感谢你把这个发布出来!

无论如何,我最近把它放在我仍在工作的网站上,并注意到移动设备上的一些不一致之处。 有时一切都会加载,但有时会丢失或不完整。 截图如下。

你会碰巧知道会发生什么吗? 或者如果我做错了什么?

带有“welcome”作为文本的大字体是一个 .otf 文件 (restgold.otf)
带有“Hi my name is...”的小文本是一个 .ttf 文件(Raleway-Medium.ttf)
如果您需要字体文件,请告诉我!

设备:iPhone7
IOS:14.1
浏览器:Safari

包装详情:
“三”:“^0.122.0”,
“三驾马车”:“^0.35.0”,
“三驾马车”:“^0.35.0”,

IMG_1509
IMG_1510
IMG_1511
IMG_1512

所有47条评论

感谢您报告此事! 您不是第一个在 iOS Safari 中描述此类问题的人,但我之前无法重现它。 我会尝试使用您的网站,希望我能够复制它。

您是否偶然通过drei使用它? 还是直接?

@lojjic我直接使用这个包和three.js。 我拥有三个实用程序的原因是在某些情况下我还使用了您的 createDerivedMaterial 函数。

感谢您对此进行检查!

我能够重现在 iPhone 8 上加载您的网站的问题。我还没有时间开始调试,但我只想承认该错误是可重现的。

@atlmtw @lojjic我在一个使用多种字体的项目中遇到了同样的问题。 我发现的唯一解决方法是在整个网站上为此浏览器使用独特的字体。

+1
每个场景有多种字体 = 某些字体永远不会出现在 iphone X、iphone SE 上

我正在尝试深入研究这个问题,但我现在无法重现它。 和以前一样的 iPhone 8。 我无法再在designsdalena.com 上复制它,但该站点可能已更改为不再使用troika-three-text 或以其他方式解决它。

所以我正在尝试使用多种字体创建一个最小的测试用例,并且不能让它失败:

https://uqgxq.csb.app/

有没有其他人能够在我可以用来测试/调试的地方重现这个?

@lojjic

为了确认,我确实换了别的东西。 虽然我更喜欢使用三驾马车的体验。

@atlmtw感谢您的确认。 我不认为您在源代码管理中拥有可以发送给我的旧版本网站? 我正在努力重现这一点,而你的似乎是一个可靠的复制品。

嘿@lojjic
这有什么好运气吗? 当在 iPhone 上使用 >1 字体时,我也看到了这一点(适用于 iPad 和 macOS)。 奇怪的是,这并不是一直可复制的,只会发生 1-2/10 次,并且仅在第一次加载时发生。 可能与字体文件下载有关?

顺便说一句,喜欢这项工作:100:

@amitrajput1992不,我仍然无法构建可重现的测试用例。 你有我可以用的吗?

@lojjic
试试这个
如果您在桌面上打开,您应该会看到 6 种不同颜色的不同文本。
我和我在一些设备上测试了这个链接,在 BrowserStack 上测试了一些,都显示了渲染问题。 刷新链接几次就可以了,这很奇怪。

这是我在 BrowserStack 上看到的。 这是在 Iphone 8 + Safari v13 上
Screenshot from 2021-06-10 19-01-09

这个在我的 iPhone 11 + Safari 14 上
E81012E6-0B7F-44CE-8E52-03729D73BD28

这可能与字体文件在网络工作者中下载的事实有关吗? 我们知道 Safari 对网络工作者来说可能很痛苦

@amitrajput1992谢谢,我确实可以在该页面上复制该问题。 我会看看我是否可以从那里调试和/或在最小化的本地测试用例中复制它。

我们知道 Safari 对网络工作者来说可能很痛苦

我也听过其他人这么说,使用工人绝对是罪魁祸首,但我无法找到有关 Safari 中工人的已知错误的任何细节。 你有细节可以分享吗?

@lojjic
听起来不错。 如果我能以任何方式提供帮助,请告诉我。 同时,我将继续调试并尝试缩小问题范围。

我也听过其他人这么说,使用工人绝对是罪魁祸首,但我无法找到有关 Safari 中工人的已知错误的任何细节。 你有细节可以分享吗?

我不知道这里的确切问题,部分原因是我在任何地方都找不到这些(或者人们没有记录这些),但这是我在修补时注意到的。 react360 以前的 react-vr(现已废弃)用于在 web worker 中运行整个 react 代码,并且对主线程的更新太慢了。 它可以很容易地在 300 毫秒到 500 毫秒左右的任何地方进行单击操作,以传播到工作线程中的单击侦听器,并且通常也会错过几次单击。
我维护了一个 repo,它是三个 gif 渲染器,最初尝试使用屏幕外画布,但结果很糟糕,并导致连续帧上的纹理混合。 将整个事情移到主线程大大改善了它。

我觉得这可能与将信息从工作线程传输到主线程时使用的结构化克隆算法有关。 虽然我还没有找到围绕 iOS 限制的可靠证据

我认为我应该首先关注这些工件,它们并不总是出现,但有时会出现:

Image from iOS

在这些情况下,布局和 SDF 生成显然完成并返回到主线程,但一些 SDF 似乎在某些地方反转了内部/外部填充。 如果这些字符的路径数据不完整,例如只有一半的路径段,我可以看到会发生这种情况。

如果在字体加载期间发生了某些事情,其中​​字体的数组缓冲区被截断或损坏,我认为这可能会导致这种观察到的症状。 同样,如果在某些地方截断,它也可能导致完全空的结果。

我将对此进行调查(也许 XHR 会给出部分数组缓冲区响应?),但第一步是将其放入一个可重现的测试用例中,我可以在本地修改和运行该测试用例。

这就说得通了。 arraybuffer 损坏可能是这里的罪魁祸首。
我看到另一个关于使整个过程在主线程上运行的讨论。 这在路线图上吗?

另外,如果有帮助,我正在使用带有以下版本的 drei 的三驾马车:
@react-三/纤维:6.2.3
@react-三/drei:6.0.1
三驾马车:0.42.0
三:0.129.0

在主线程上运行是可能的,但会导致阻塞主线程几秒钟的非常糟糕的体验。 那应该只是最后的手段。

你的测试页有变化吗? 似乎它现在只对所有不同的文本对象使用一种字体,至少在 iOS 上......? 不过,有时我仍然会看到带有该单一字体的乱码 SDF,这意味着这可能会因多种字体而加剧,但不限于此。

我确实为 iOS 设备添加了一个后备选项,以便为整个应用程序仅使用一种字体。 这是我的生产环境,所以不能在那里破坏东西。
我将在我的暂存环境中创建另一个示例,并尽快在此处发送一个链接。

很难发现这仍然发生在单一字体上:facepalm:

嗯,实际上似乎我只能在连接到 Safari devtools 时使用您的新单一字体出现错误,然后它一直存在错误。 不确定这是否给我们任何线索。

好吧,还有一点进步......我已经验证我能够通过截断单个字形的路径命令来强制执行上面看到的相同的部分字形伪影。 我还不能确定这是否是由于原始字体数据不完整(我认为这只会导致一个部分字形,而不是很多,所以似乎不太可能),或者是否有什么原因导致 for 循环提前退出(这似乎是不可能的,但也许有一些奇怪的 JIT 错误)。

无论哪种方式,我都遇到了 Safari 的 USB 连接开发工具无法在相关代码中设置断点的问题。 @amitrajput1992是否有可能将您的测试应用程序作为可以在本地构建/运行的源文件,所以我可以尝试换出三驾马车代码进行调试?

@lojjic虽然我无法共享原始应用程序代码,但让我设置一个与我在生产应用程序中使用的结构相似的故事书存储库,并为此添加一个测试渲染。 稍后将通过链接发送。

@lojjic
我在这里设置了一个与我的生产应用程序结构相似的基本复制: https ://github.com/amitrajput1992/r3f-experiments
我可以在我的 iPhone 11 和 BrowserStack 上复制同样的问题。
还在这里发布了故事书以便于访问https://amitrajput1992.github.io/r3f-experiments

@amitrajput1992感谢您的测试用例! 在修复从您的 gmetri 站点加载字体的 CORS 错误后,我可以将其复制到那里,方法是从故事书中提供它们。

但是...然后我的 Safari 开发工具就在尝试连接到它! 🤦🤦🤦🤦🤦🤦 所以我什至无法添加 console.log 语句并查看它们。 这个bug真的不想修复,对吧?

感到沮丧; 明天我会尝试以更新鲜的方式回到这个问题上。 如果您有任何想法,请告诉我。

@lojjic ,我现在没有mac系统,但我在浏览器堆栈上用本地转发测试了这个。 看起来 web-worker 与主线程中记录的 sdf 数据是不同的。 这可能是由于线程通信之间的序列化-反序列化过程,但不完全确定。 我会继续调试这个。
如果 safari dev-tools 不适合您,您可以尝试跨浏览器测试,他们提供 100 分钟的试用期,这可能会有所帮助。

无法在相关代码中设置断点

愚蠢的建议是在每行代码和 console.log 之后从 webworker 抛出消息,因为你们能够重现错误。

我的 iPhone 6/11 上的图片:

愚蠢的建议,在每行代码和 console.log 之后从 webworker 抛出消息

根本不是一个愚蠢的建议! 这正是我想要做的,但是当我指向本地可编辑实例时,Safari 的 devtools 会立即崩溃,所以我什至看不到 console.log 输出。 :(

您是否尝试在连接的 iPhone 中打开localhost url? 在这种情况下,端口转发如何工作?

您是否尝试在连接的 iPhone 中打开 localhost url? 在这种情况下,端口转发如何工作?

我正在通过本地网络 IP 地址从 iPhone 访问开发服务器。 我也尝试通过https://localhost.run 进行管道传输。 在这两种情况下,Safari devtools 一打开它就会崩溃。 页面本身呈现得很好(尽管有时会出现错误。)

我在一些博客上读到这可能在两种情况下发生:

  1. 当手机电量为 100% 时
  2. 通过网络而不是电缆连接进行调试时

这是类似行的长期运行线程,但没有解决方案https://developer.apple.com/forums/thread/92290

但是当我指向本地可编辑实例时,Safari 的 devtools 会立即崩溃,所以我什至看不到 console.log 输出。 :(

可以用这样的东西替换默认的 console.log 函数

console.log = (msg) => document.getElementById("my_ios_console").innerHTML += msg;

但您需要在 html 页面或 JS 脚本中创建该 div

<div id="my_ios_console" style="position: absolute; top:0; left: 0; background: white"></div>

这应该在主线程上显示所有控制台消息

谢谢@munrocket ,这可以工作,我会试一试。

大家好,

对不起,我离这个话题太远了。 Idk 如果这有助于调试,但最近的 Xcode 13 版本(测试版)模拟器已经能够很好地运行我的 3D localhost 的东西! 我遇到了你们之前讨论过的问题,它一直与早期版本崩溃。

@lojjic这个运气好吗?

这有什么好运气吗?

不,很遗憾,我最近没能在这方面投入太多时间。

有没有可能关闭网络工作者? 只是为了检查

大家好,

我在一个项目中偶然发现了同样的问题(不幸的是我无法共享代码)并最终在这里找到了解决这个问题的方法。 由于上一次更新是在一个多月前,我今天决定弄乱我的项目的依赖代码,希望能查明到底发生了什么,以及哪些代码行导致了这场 UX 灾难。

在我继续之前,我想强调以下信息和调整不以任何方式建议,在这里共享纯粹是为了帮助寻找实际的解决方案。 以下信息不是解决方案。 你已经被警告过了。

第一的。 是的,正如前面讨论中提到的,这似乎确实是 iOS Safari 中的 WebWorker 的具体错误。 Firefox (win10)、Chrome (win10)、Opera (win10)、Safari (macOS big sur) 等不存在此问题,字体 100% 正确加载。 然而,Safari (iOS) 在多个 WebWorkers 之间遇到了某种竞争条件(我还没有确定这是否完全正确,也没有确定哪些异步调用相互干扰)。

第二。 当通过 Troika 的Typr依赖项中的 readShort 函数访问时,这种所谓的竞争条件(或任何情况)导致包含正在加载的字体数据的缓冲区产生一些 NaN 值。 那么,问题实际上在 Typr 中吗? 可能。 我不确定。 然而,这几个 NaN 值级联调用堆栈,从字面上破坏了一切,最终导致字形显示完全错误。

第三。 在确定了我需要的确切位置( Typr/bin.s中的这个 readShort 函数)之后,我用很多方法对其进行了调整以了解发生了什么。

        readShort : function(buff, p)
    {
        //if(p>=buff.length) throw "error";
        var a = Typr._bin.t.uint8;
        a[1] = buff[p]; a[0] = buff[p+1];
        return Typr._bin.t.int16[0];
    },

当我简单地使用 console.log(Typr._bin.t.int16[0]) 时,应用程序会打印一些不应该打印的 NaN(小心尝试,因为整个应用程序可能会挂起打印的东西 - 这个函数被调用数千次,具体取决于用例)。 但是,正如预期的那样,在此函数内的任何位置暂停应用程序(使用调试器关键字或断点,甚至访问控制台)会导致值自行更正而不产生 NaN(这让我相信竞争条件)。 这意味着您无法以常规方式使用调试器检查问题。

第四也是最后。 如果不是为了找到这个问题的实际解决方案,我建议不要这样做。 请注意,我在上面写道,即使在 readShort 函数中使用了控制台,NaN 也会消失。 所以我巧妙的黑客思维认为在 readShort 的返回语句之前包含这个片段是一个绝妙的主意:

if (Number.isNaN(Typr._bin.t.int16[0])) {
    console.log()
}

它奏效了! 现在,所有文本在 iOS Safari 以及我之前测试过的所有其他浏览器中都可以正常显示。 问题解决了~...有点,以最糟糕的方式。 事实证明,应用程序为访问控制台而创建的简短窗口解决了所谓的竞争条件。 请注意,它仅在连接到控制台时才会这样做。

综上所述。 这就是我所在的地方。 糟糕的解决方法有效,但我仍然寻求一个实际的解决方案,就像这里的每个人一样。 事实证明,问题可能出在 Troika 中,也可能不在 Troika 中,因为它可能一直存在于 Typr,甚至是 iOS 的 WebWorker 实现(谁知道)。 无论如何,我希望所有这些信息对调查有所帮助,我们都会看到这一点。

参考调用栈:
Typr/bin.js - readShort
Typr/glyf.js - _parseGlyf
Typr/Typr.U.js - _drawGlyf
Typr/Typr.U.js - glyphToPath
Troika/FontParser_Typr.js -(匿名)forEachGlyph
三驾马车/FontParser_Typr.js - wrapFontObj
Troika/FontParser_Typr.js - 解析
...工人的东西

还有@lojjic ,关于使用 MacOS Safari 通过 USB 调试 iOS Safari 的故障排除:
如果 MacOS Safari DevTools 坚持无限期加载或显示页面崩溃或未加载脚本等消息,我建议尝试断开并重新连接到本地网络或您的手机。 要么这样,要么尝试关闭并重新打开 DevTools 几次。 然后明显刷新手机上的网页。 我这样说是因为这在我今天发生了几次(痛苦)并且我以这种方式解决了它(MacOS Big Sur 和 iOS 15.0.1 之间的连接)。

OMG @malulleybovo我从假期回来,看到了你的发现,哇,真是一个惊喜! 😃 非常感谢你深入研究这个。

仅仅知道 readShort 正在产生 NaN 就可能在最终理解这个问题上向前迈出了一大步,正如你所知,我已经完全坚持了很长一段时间。 我换了工作并失去了对我正在使用的 iOS 设备的访问权限,这于事无补。

我的下一个问题是我们能否确定_为什么_ Typr._bin.t.int16[0] 读取产生的是 NaN? 似乎它必须在其中一个缓冲区中获得不正确的值(字体的buff或实用程序Typr._bin.t.buff ),但它有助于准确了解 buff/uint8/int16 的值是在那个时间点与他们应该是什么。

您可以在其中插入 console.log() 以避免错误的事实很奇怪。 我不确定这是否表示竞争条件,或者访问控制台可能会使其退出 JIT 模式。 我希望是前者,因为这听起来更容易检测和解决。

@lojjic 恭喜换工作!

我现在只是对这个问题做了更多的挖掘,我得到了更多有趣和奇怪的消息。 回到我之前分享的 readShort 代码片段,我尝试查看数组值(使用共享数组缓冲区),发现了迄今为止我在软件工程职业生涯中见过的最奇怪的事情。

        readShort : function(buff, p)
    {
        //if(p>=buff.length) throw "error";
        var a = Typr._bin.t.uint8;
        a[1] = buff[p]; a[0] = buff[p+1];
        /***** Right here, I peeked at Typr._bin.t.int16, Typr._bin.t.int8, and Typr._bin.t.uint8 ******/
        return Typr._bin.t.int16[0];
    },

在我的应用程序中查看 readShort 中 NaN 的第一次出现时,我发现 buff[p]=255 和 buff[p+1]=6(都是有效的 uint8 值)。 考虑到这一点,我查看了 Typr._bin.t.uint8 的值,发现它具有预期的 [6, 255, 0, ...] 。 然后我偷看了 Typr._bin.t.int16 并发现错误的 [NaN, 0, ...] 而不是 [-250, 0, ...]。 最后,我偷看了 Typr._bin.t.int8 并且......它也是错误的......它是 [6, NaN, 0, ...] 而不是 [6, -1, 0, ...] .

Typr glyf 库在多个不同类型的数组(Uint8Array、Int8Array、Int16Array 等)上使用一个共享的 ArrayBuffer。 这一事件向我表明,在 iOS Safari(仅限)中,在更改其中一个数组后,其他数组上的值可能不会立即更新。 不知道为什么,但我在最近的历史中发现了一个涉及 iOS Safari 中的 ArrayBuffer 的已解决错误报告,这使得这更加可信......被证明有缺陷一次,很可能被证明有两次缺陷(参考:(https://bugs.webkit .org/show_bug.cgi?id=194268)[https://bugs.webkit.org/show_bug.cgi?id=194268])。

发现这一点后,我决定尝试(uint8,uint8) to int16转换的替代实现。 这次使用按位运算。 我使用的代码如下:

        readShort : function(buff, p)
    {
        var a = buff[p + 1] + (buff[p] << 8);
        if (a > 0b0111111111111111) {
            a = (~a) + 1;
        }
        a = (a < 0 ? -1 : 1) * (a & 0b1111111111111111);
        return a;
    },

你有它。 所有带有字体的文本现在总是正确显示(即使没有连接到 devtools - 请参阅我之前关于 console.log 的评论以了解此免责声明)此替代解决方案修复了 iOS Safari 中的问题(在 iOS 15.0.2 上测试) , 并继续在我之前测试过的浏览器中运行,就像以前一样,例如 Chrome v95.0.4638.54 (win10)、Firefox v93.0 (win10)、Opera v80.0.4170.63 (win10) 和MacOS Safari (MacOS Big Sur v11.3.1)。

*如果有人可以优化我上面的代码片段,请随意~

最后,在我看来这个问题不是由三驾马车引起的。 三驾马车似乎实际上正在遭受更深层次问题的后果。 所以我会亲自将这个问题转移到 Typr。 但我知道什么...自己测试一下,让我们争论这是否真的是问题的根源。 ;)

我认为@malulleybovo应该得到一个奖项或什么的! 🥳

这太棒了,缩小范围并提出避免该问题的替代实现! 非常感谢你!

我很高兴将您的readShort解决方案集成为 troika 中的本地覆盖和/或 Typr 中的上游。 我们可能还想要其他 readFoo 方法的替代实现?

一般来说,typed-arrays-sharing-a-buffer 模式似乎有问题/危险。 现在想想,这是一个非常奇怪的模式。 似乎DataView正是为了从二进制读取各种数字格式的目的,没有在 uints 和 JS 数字之间进行任何奇怪的值转换或字节序不一致......我想知道这是否也能解决问题? 可能是这样的? https://gist.github.com/lojjic/94d7b5f5f374598fe0e9761be45ebb2b

感谢@lojjic 的赞美~我很高兴我能帮上忙。

您提出的解决方案似乎很有希望,所以我只是对其进行了测试并猜猜看,它也可以工作(在我之前列出的所有浏览器上)!
如果您问我,使用 DataView 似乎是在 JS 中实现此功能的一种简洁而正确的方法。 好东西。

我的应用程序依赖于 Typr 的 glyf 脚本,它使用 Typr 的 readInt8、readShort、readUshort 和 readBytes。 尽管出于测试目的,我已经包含了您的完整解决方案,但我仅在这些功能上对其进行了测试。 从外观上看,一切都有效。

为了更深入地了解此解决方案的有效性,我将测试其他场景。 但是我缺乏具体的例子来测试这些(除了单元测试)。

我相信来自 bin.js 的 Typr 的 readFixed、readF2dot14、readUshorts、readUint64、readASCII、readUnicode、readUTF8、readBytes 和 readASCIIArray 不需要更改,因为它们不直接使用类型化数组。 因此,只有您的要点中的功能需要在 Typr 中进行更改。 此外,随着这一变化,Typr 的共享 ArrayBuffer 和类型化数组将变得过时。

如果更多的开发者可以对此进行测试并给予批准,我们将对解决方案更有信心。 这是因为我可以使用的测试用例和测试设备数量有限,而且测试结果存在偏差的可能性很小。

您提出的解决方案似乎很有希望,所以我只是对其进行了测试并猜猜看,它也可以工作(在我之前列出的所有浏览器上)!
如果您问我,使用 DataView 似乎是在 JS 中实现此功能的一种简洁而正确的方法。 好东西。

惊人的!!! 我简直不敢相信。 🎉🥳

我将对此进行更多测试,看看我是否可以验证其他功能,并进行基本的性能比较。 除非出现讨厌的东西,否则我会尽快得到这个集成的。 我非常有信心将它包含在三驾马车版本中,以便人们可以尝试一下; 如果出现任何问题,社区会通知我们。 一旦它在野外出现了一点,我会将它提交给 Typr。

性能似乎相当,在某些情况下甚至更快。 额外的胜利! 😄

我已经验证了其他功能也可以工作。 我不得不稍微修改_view帮助器以处理 CFF 字体中 Typr 将buff作为普通 JS 数组而不是 Uint8Array 传递的情况。

我已经发布了 troika-three-test 版本0.43.1-alpha.0 ,其中包含 DataView 修复(当前使用 Typr 的私有分支 -相关提交

任何有能力的人(@amitrajput1992?@strangerintheq?@atlmtw?),我将非常感谢使用此版本进行测试以验证它是否解决了您特定应用程序中的问题。 我将尝试使用 Browserstack 或寻找借用的 iPhone 做同样的事情。 提前致谢!

@lojjic很高兴听到有解决方案。 让我快速测试一下,然后回复你。

@amitrajput1992嗨,你有机会测试 alpha 吗? 我想发布它,并希望得到额外的验证。 :)

@lojjic嘿,我刚刚有时间对此进行测试。 看起来它现在正在工作!

在此处查看更改: https: //amitrajput1992.github.io/r3f-experiments/?path=/story/testers --text-tester

我已经发布0.44.0版本,修复了这个讨厌的错误。 我很高兴终于解决了这个问题! 感谢大家的帮助,尤其是@malulleybovo ,感谢您深入挖掘我无法找到的根本原因。 我非常感谢! 🥳

此页面是否有帮助?
0 / 5 - 0 等级