昨天把Android的VectorDrawable不能rotate 90度的bug给提了issue.
早上起来check邮件的时候已经变为assigned了,大概确实是个bug了.
这个的原因之前也大致提过下.
基本就是算误用了transform Matrix的一些维度吧.
在旋转90度的时候,这个3*3 matrix的MSCALE_X和MSCALE_Y项目会是近似0.
而VectorDrawable的draw实现是直接拿这两个值乘width/height做scaling的.
其结果是算出个零,只是short path return什么都不做了.
于是结果就是rotate 90度的时候,canvas上什么都没有.
看了下注释,提到用这两个值的原因是避免blur.
翻了下commit log,最近的改动的引入也确实是为了解决这个原因.
不过就实际经验来说,抛开90度旋转的问题,这个blur还是存在的.
这个在自己做animation的时候,从0到90度之前的几帧可以看到.
而且翻看了下目前的具体实现,貌似还不是直接走的canvas的通道.
而是draw到一个临时的canvas的bitmap上面,再把这个bitmap draw回提供的canvas上面.
倒是有些不知道当初是如何定位到blur的问题跟这个有关系的.
下午简单地实现了一个半成品的VectorDrawable.
直接是draw到提供的canvas上面,加上animation也没发现有blur的问题.
不过也可能是因为有些功能并没有完全实现的原因.
毕竟,自己写的只取了vector xml定义里的部分值.
一个是vector element的viewportwidth/height.
这个主要是拿来算scale的.
毕竟,虽然说上面提到的Matrix里有两个值有时候能拿来直接动作scale系数.
但终究来说,这个matrix事实上可能是一系列transform的composition而不是单一的scale matrix.
所以直接取值是不可取的.
因此,需要一个svg/vector graph的原始大小定义,然后再通过在canvas上想要paint的bounds的大小一起算scale系数.
另一个是path element的pathData.
这个是类SVG的command string.
也就是实际的SVG/Vector graph的定义.
之前用javascript写的SVG也只用了lineto/moveto/cloase几个command,所以生成的SVG定义也只有这些.
本来想着直接导入的.
但Android的vector resource跟SVG的还不完全一样.
所幸的是这个command序列还是语意相同的.
也少了写麻烦.
所以在写这个的parser的时候,也只支持了这几个命令.
不过看了下,要加其他的话,倒也不难.
毕竟都是直接map到canvas的对应方法上面的.
而且基本上这个的parser也没什么好写的.
本身提供了XmlResourcesParser,自己只要实现个command string的parser就行了.
不过由于这个drawable到底不是原生的drawable,所以要取/构造还是有点不够友善的.
一般来说,都是直接拿context,然后直接通过auto generate的R id去拿drawable.
而现在,这个R id也还是指向原生的VectorDrawable的.
一个思路当然是去hack这个generate的过程,让它指向自己的这个实现.
不过明显的这个成本太高,侵入性太强.
估计至少要动到对应的plugin或者Android Studio.
退一万步说,即使找到了侵入点,那到底也是不兼容的改动,后面纯粹的升级维护纯粹是给自己找麻烦.
所以只能自己直接构造了.
要解决的第一个问题自然是怎么去读vector xml了.
文件路径倒是一目了然.
解析的话,如果不用XmlResourcesParser,随便用sax什么的也OK.
不过这种本身就已经侵入性很强的改动,就没必要添加无谓的不确定/稳定因素了.
翻了下原生实现的locate过程,其实也简单.
拿到AssetManager直接open就行了.
剩下一个就是文件路径的问题.
直接硬编码路径也OK.
但总体来说,不算一个特别优雅的方式.
跟了下相关代码,用R id去locate也不麻烦.
拿到对的Resources直接get value得到的就是了.
这里的问题有两个.
一个是Resources.
本身是有个Resources.getSystem()的.
不过从名字上看就知道是非app specific的.
app specific的也还是只能通过context拿.
另一个问题就是get到的TypedValue.
这里拿到的确实也是路径.
不过需要用value.string这种不太好看的方式来拿.
这里的点子啊与string是个public的field.
虽然说方便,不过看起来终究是有些碍眼.
奈何也没其他稍微顺眼点的方式.
然后既然xml读到了,也parse完了,构造自然是没什么问题了.
剩下的就是一些cache相关的.
原生的drawable一般都会带有个ConstantState,基本上就是对应drawable的实际image数据或者定义.
想想也不难理解.
像image的话,总不能每次都load一次.
所以有个ConstantState的设计,倒也挺符合直觉的.
只是对应的方法倒不是强制overide的,这点有点不太舒服.
毕竟原则上来说可以是abstract强制一下.
不过也无所谓了.
个人喜好问题.
其他的也就没什么了.
说白了就是基本上所有drawble都是到canvas的.
拿到canvas,什么都好说.
不过有一点就是,canvas这个并不是线程安全的.
因为其实也是一个transform的composition,多一个不同batch的modify一起concurrent的话,结果挺难预料的.
有想过看看能不能clone一下,然后parallel batch一下,最后在一个个apply/merge回来.
因为底层估计也是一些matrix的运算,应该可以独立.
不过看到是native的操作,一时也懒得去拉代码看开销,于是就算了.
当初写custom viewgroup的时候就想过.
如果现在的render pipeline对visual region/canvas的invalide能像NUMA一样,分块管理/invalidate的话,估计反而能省一些事.
直接invalidate所属的physical region就好了,交给邮件处理,而不是在拼命算dirty region.
当然,这个也可以软件模拟就是了.
每个visual element assign一个logical region,然后dirty就dirty整个region,然后每个run就batch update/redraw dirty就行了.
之前写custom viewgroup的layout的时候大致也是这个思路.
而且由于采用的取巧的top align的方式,one pass就OK,所以能直接parallel.
如果是像bottom align之类的,可能就不行了.
由于每放置/slice一块区域就可能得重新调整line height.
因为新加的元素的高可能超过了当前的高度,为了对齐得把该行的line height调整到行内最高的元素.
于是,就至少得对之前元素的offset bottom作调整.
无可避免地对整行做重新的layout计算.
所以,这里的一个思路就是,如果现代浏览器做布局的时候基本算法也是如此的话.
那么align-top和提取fix box width/height的话,估计对render性能有点影响.
不过涉及到GUI的,实际开销和代价值不值得,甚至有没必要就是另一回事了.
毕竟,这种有视觉元素的跟纯粹服务端的思路还是很不同的.
后者的哲学在于感觉不到存在.
无论是从性能还是容灾方面来说都是.
而带视觉效果的,评价体系就是相对离散化和多态了.
毕竟,人的视觉系统是一个有着明显边界分段的函数.
订阅:
博文评论 (Atom)
爽文
去看了好东西. 坦白说,多少是带着点挑刺的味道去的. 毕竟打着爱情神话和女性题材的气质,多多少少是热度为先了. 看完之后倒是有些新的想法. 某种程度上来说,现在的年轻人或者说声音就像小叶. 只要说点贴心的话就能哄好. 也是那种可以不用很努力了. 留在自己的舒适区避难所小圈子抱团就...
-
最近尝试了下海淘. 当然,方向上来说是从国内到新加坡. 先是买了个iPhone,算上运费和双重征税,到手比官方还是便宜个一两百新的. 换算回来也不多事10%的纯粹价格因素差异. 当然,之类有电商促销的因素. 也有比较基准是新加坡Apple Store售价的原因. 但如果同样比较A...
-
这两天看完了Netflix版的三体. 某种程度上来说,完成度还是不错的. 尽管开始的时候对于第一集片头有些争论,但整体如果带入当下去看的话,还是有些梗的. 比如三体对于地球科技的发展速率的担忧,由此衍生的智子. 以及现有力量对比上的压倒性优势. 如果带入中美关系以及各自的历史阶段...
-
前几天Sora出来后才仔细看了下diffusion,发觉确实算挺取巧的. 按照naive的intuition或者说不那么现代的方式的话,可能需要segmentaion为基础的composite的方式去生成图片,即使扯点deep learning/network的,可能也是类似一些...
没有评论:
发表评论