Android4.2文本渲染增强之应用GPOS

码农中,对于那些只会调用API的做法总是嗤之以鼻。虽然,掌握很多APIs的用法并不一定是什么多么令人自豪的事情,但如果没有掌握足够多的常用API,如STL,Java 标准库等的用法,则多半是不那么光彩的。 

早期的android,在文本渲染部分一直有一个Bug,即,对于像泰语、印度语这类复杂语系,没有应用OpenType字库文件的GPOS信息。在Google的原生Code中,这个Bug甚至在4.1 Jelly Bean 中都一直存在。 其实在4.0 ICS,引入了OpenType Shaping引擎Harfbuzz,已经能够正确的获取GPOS这些信息,只是这些信息以前是直接被丢弃不用罢了。 

对于这个问题,其实做android的各家,自己都有在提供解决方案。一位前辈的解法为:在Skia中开了一路接口出来,SkCanvas->SkDevice->SkDraw->SkScalerContext 等,以便于GPOS的这些information可以被带下去,以便于在往Canvas中画字时可以被应用到。

 在android 4.2中,这个问题已经得到了适当的处理,其中比较重要的一段Code如下:

721        // Get glyph positions (and reverse them in place if RTL)
722        if (outPos) {
723            size_t countGlyphs = mShaperItem.num_glyphs;
724            jfloat x = totalAdvance;
725            for (size_t i = 0; i < countGlyphs; i++) {
726                size_t index = (!isRTL) ? i : countGlyphs - 1 - i;
727                float xo = HBFixedToFloat(mShaperItem.offsets[index].x);
728                float yo = HBFixedToFloat(mShaperItem.offsets[index].y);
729                // Apply skewX component of transform to position offsets. Note
730                // that scale has already been applied through x_ and y_scale
731                // set in the mFontRec.
732                outPos->add(x + xo + yo * skewX);
733                outPos->add(yo);
734#if DEBUG_GLYPHS
735                ALOGD("         -- hb adv[%d] = %f, log_cluster[%d] = %d",
736                        index, HBFixedToFloat(mShaperItem.advances[index]),
737                        index, mShaperItem.log_clusters[index]);
738#endif
739                x += HBFixedToFloat(mShaperItem.advances[index]);
740            }
741        }
这段Code的主要作用为,将Harfbuzz返回的数据做一个格式转换,转换为SkCanvas::drawPosText()可用的形式,一个是数字的格式的转换,即由Harfbuzz shape时所用的单位转换到float型的像素值,另外就是满足drawPosText()对于数据放置位置的要求,SkCanvas::drawPosText()的原型为: 

705    /** Draw the text, with each character/glyph origin specified by the pos[]
706        array. The origin is interpreted by the Align setting in the paint.
707        @param text The text to be drawn
708        @param byteLength   The number of bytes to read from the text parameter
709        @param pos      Array of positions, used to position each character
710        @param paint    The paint used for the text (e.g. color, size, style)
711        */
712    virtual void drawPosText(const void* text, size_t byteLength,
713                             const SkPoint pos[], const SkPaint& paint);
在JNI的Canvas.cpp中可以看到另外的变化:

819    static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count,
820            jfloat x, jfloat y, int flags, SkPaint* paint) {
821        // Beware: this needs Glyph encoding (already done on the Paint constructor)
822        canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint);
823    }
824
825    static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray,
826            int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) {
827        SkPoint* posPtr = new SkPoint[count];
828        for (int indx = 0; indx < count; indx++) {
829            posPtr[indx].fX = SkFloatToScalar(x + posArray[indx * 2]);
830            posPtr[indx].fY = SkFloatToScalar(y + posArray[indx * 2 + 1]);
831        }
832        canvas->drawPosText(glyphArray, count << 1, posPtr, *paint);
833        delete[] posPtr;
834    }
上面的doDrawGlyphs() 在android 4.2已经被弃置不用了,实际在执行的为doDrawGlyphsPos()函数。可以看到原来使用SkCanvas::drawText() 也是遭遇了被弃置不用的命运,在新版中,有改采SkCanvas::drawPosText()这个函数。 Google的这个解法,明显要简洁的多。 

看到Google的解法,对比之前看到的解法,实在是不能不令人感叹,“API不是万能的,但不懂API是万万不能的”。对于码农来说,熟悉API的用法,大概就好象修理工熟悉自己的钳子、螺丝刀一样重要吧。

转载于:https://my.oschina.net/wolfcs/blog/104977

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值