文字绘制主要包括编码转换(主要是中文)、字形解析(点线或image)和实际渲染三个步骤。在这个过程中,字形解析和实际渲染均是耗时步骤。Skia对文字解析的结果做了一套缓存机制。在中文字较多,使用多种字体,绘制的样式(粗/斜体)有变化时,这个缓存会变得很大,因此Skia文字缓存做了内存上的限制。
C++ SKIA文字绘制
C++ SKIA路径绘制
SkPath类
SkPath结构
去除成员函数之后,我们看到SkPath包括这几个成员,注释中补充了说明
class SK_API SkPath {
//SkPath中的主要内容,SkAutoTUnref是自解引用,之所以这么设计,是为了复制SkPath时,省去份量较多的点复制(只复制引用)。
//由一系列线段组成
SkAutoTUnref<SkPathRef> fPathRef;
int fLastMoveToIndex;
uint8_t fFillType;//如下四种类型之一
/*enum FillType {
kWinding_FillType,//绘制所有线段包围成的区域
kEvenOdd_FillType,//绘制被所有线段包围奇数次的区域)
kInverseWinding_FillType,//kWinding_FillType取反,即绘制不在该区域的点
kInverseEvenOdd_FillType//第二种type取反
}*/
mutable uint8_t fConvexity;//凹凸性,临时计算
mutable uint8_t fDirection;//方向,顺时针/逆时针,临时计算
#ifdef SK_BUILD_FOR_ANDROID
const SkPath* fSourcePath;//Hwui中使用,暂不关注
#endif
};
关于 fFillType中 kWinding_FillType和 kEvenOdd_FillType的区别,可看SkPath::contains。这是判断点是否在不规则几何体内的经典代码(),很有参考意义。
C++ SKIA渲染架构
从渲染流程上分,Skia可分为如下三个层级:
- 指令层:SkPicture、SkDeferredCanvas->SkCanvas。 这一层决定需要执行哪些绘图操作,绘图操作的预变换矩阵,当前裁剪区域,绘图操作产生在哪些layer上,Layer的生成与合并。
- 解析层:SkBitmapDevice->SkDraw->SkScan、SkDraw1Glyph::Proc。 这一层决定绘制方式,完成坐标变换,解析出需要绘制的形体(点/线/规整矩形)并做好抗锯齿处理,进行相关资源解析并设置好Shader。
- 渲染层:SkBlitter->SkBlitRow::Proc、SkShader::shadeSpan。 这一层进行采样(如果需要),产生实际的绘制效果,完成颜色格式适配,进行透明度混合和抖动处理(如果需要)。

C++ SKIA绘制虚线
DashPathEffect是PathEffect类的一个子类,可以使paint画出类似虚线的样子,并且可以任意指定虚实的排列方式.
/** intervals: array containing an even number of entries (>=2), with
the even indices specifying the length of "on" intervals, and the odd
indices specifying the length of "off" intervals.
count: number of elements in the intervals array
phase: offset into the intervals array (mod the sum of all of the
intervals).
For example: if intervals[] = {10, 20}, count = 2, and phase = 25,
this will set up a dashed path like so:
5 pixels off
10 pixels on
20 pixels off
10 pixels on
20 pixels off
...
A phase of -5, 25, 55, 85, etc. would all result in the same path,
because the sum of all the intervals is 30.
Note: only affects stroked paths.
*/
static SkPathEffect* Create(const SkScalar intervals[], int count, SkScalar phase)
以上是官方的代码注释。
C++ glog使用
概述
Google glog是一个基于程序级记录日志信息的c++库,编程使用方式与c++的stream操作类似,主要支持功能:
- 参数设置,以命令行参数的方式设置标志参数来控制日志记录行为;
- 严重性分级,根据日志严重性分级记录日志;
- 可有条件地记录日志信息;
- 条件中止程序。丰富的条件判定宏,可预设程序终止条件;
- 异常信号处理。程序异常情况,可自定义异常处理过程;
- 支持debug功能。可只用于debug模式;
- 自定义日志信息;
- 线程安全日志记录方式;
- 系统级日志记录;
- google perror风格日志信息;
- 精简日志字符串信息。
场景
日志适用于以下场景:
C++ Lambda表达式
场景
- lambda 表达式在很多语言里都有一席之地,因为它的原因,可以在函数里快速定义一个便携的函数,或者在函数参数里直接快速构造和传递.
- 它可以说是匿名函数对象,一般只适用于某个函数内,只做临时使用.
- 一般是需要在对某个数据临时特殊处理时使用,比如对某种参数类型进行限定的再次封装和行为约束.
lambda 语法

C++ 如何支持反射
如果你问一个IT人士“C++如何实现类似Java的反射?”,结果会怎样呢?~!@#¥%……&*,估计大部分人都会要稍微思考了一下,或者直接说“C++根本就不支持反射的呀!”。
C++ glog参数说明
logtostderr(bool, default=false)
是否把日志输出到stderr,而非文件.
Note: 这个参数可以设置为true,1或yes,当然也可以设置为false, 0或no.
alsologtostderr(bool, default=false)
除了输出日志信息到日志文件外,还同时输出到stderr.
Python 理解Main函数
在很多python脚本中在最后的部分会执行一个判断语句if name == “main:",之后还可能会有一些执行语句。那添加这个判断的目的何在?
Python 如何在py文件中调用其他py文件内的函数
假设名为A.py的文件需要调用B.py文件内的C(x,y)函数
假如在同一目录下
则只需
import B
if __name__ == "__main__":
B.C(x,y)
如果只需调用单个函数,也可以
from B import C
if __name__ == "__main__":
C(x,y)
如果跨越了层级
同目录下不同子文件夹
直接引用会报错,