Chinaunix首页 | 论坛 | 博客
  • 博客访问: 816733
  • 博文数量: 117
  • 博客积分: 2583
  • 博客等级: 少校
  • 技术积分: 1953
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-06 22:58
个人简介

Coder

文章分类
文章存档

2013年(1)

2012年(10)

2011年(12)

2010年(77)

2009年(13)

2008年(4)

分类: Android平台

2013-01-25 23:11:27

码农中,对于那些只会调用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的用法,大概就好象修理工熟悉自己的钳子、螺丝刀一样重要吧。

阅读(4865) | 评论(2) | 转发(0) |
1

上一篇:Linux 下文本处理

下一篇:没有了

给主人留下些什么吧!~~

kangear2014-08-21 13:13:40

文章可以被多嚼一会儿。有内涵。

qiandayong2013-08-01 09:57:38

楼主你好,没有gpos信息会出现什么错误?能不能举个例子?谢谢。