我有一个运行
Android 4.2.2的华硕Nexus 7我的应用程序在运行以下代码时在sk_malloc_flags中生成一个SIGSEGV:
static Picture createDrawing() { Path firstPath = new Path(); firstPath.moveTo(3058,12365); firstPath.lineTo(8499,3038); firstPath.lineTo(9494,3619); firstPath.lineTo(4053,12946); firstPath.close(); Path fourthPath = new Path(); fourthPath.moveTo(3065,12332); fourthPath.lineTo(4053,12926); fourthPath.lineTo(9615,3669); fourthPath.lineTo(8628,3075); fourthPath.close(); Picture picture = new Picture(); Canvas canvas = picture.beginRecording(12240,15840); canvas.clipPath(firstPath); canvas.clipPath(fourthPath); << SIGSEGV occurs here picture.endRecording(); return picture; }
SIGSEGV报告如下:
I/DEBUG ( 124): signal 11 (SIGSEGV),code 1 (SEGV_MAPERR),fault addr deadbaad I/DEBUG ( 124): r0 00000027 r1 deadbaad r2 4017f258 r3 00000000 I/DEBUG ( 124): r4 00000000 r5 bed72434 r6 bed72508 r7 1be773bc I/DEBUG ( 124): r8 1be730f9 r9 000042c3 sl 00000001 fp 67185010 I/DEBUG ( 124): ip 40443f3c sp bed72430 lr 401522f9 pc 4014e992 cpsr 60000030 ... I/DEBUG ( 124): backtrace: I/DEBUG ( 124): #00 pc 0001a992 /system/lib/libc.so I/DEBUG ( 124): #01 pc 00018070 /system/lib/libc.so (abort+4) I/DEBUG ( 124): #02 pc 000be4b4 /system/lib/libskia.so (sk_malloc_flags(unsigned int,unsigned int)+28) I/DEBUG ( 124): #03 pc 0008afc0 /system/lib/libskia.so (SkRegion::op(SkRegion const&,SkRegion const&,SkRegion::Op)+1716) I/DEBUG ( 124): #04 pc 00089448 /system/lib/libskia.so (SkRasterClip::op(SkRasterClip const&,SkRegion::Op)+128)
我显然简化了上面显示的代码,完整的应用程序使用基于某些输入数据的变换等来生成值.他们是否有任何关于如何解决这个问题的建议而没有在一般情况下实现我自己的裁剪代码?
解决方法
这看起来像是一个用于clipPath处理的命运不佳的角落案例.
canvas.clipPath(fourthPath);
导致与先前的firstPath合并,但由于这些是复杂的(非矩形)形状,系统会尝试将它们绘制为扫描线并在之后合并.为了进行这种合并,它需要分配一些内存,但需要分配as you can see in SkRegion.cpp,这适用于启发式最坏情况.
static int compute_worst_case_count(int a_count,int b_count) { int a_intervals = count_to_intervals(a_count); int b_intervals = count_to_intervals(b_count); // Our heuristic worst case is ai * (bi + 1) + bi * (ai + 1) int intervals = 2 * a_intervals * b_intervals + a_intervals + b_intervals; // convert back to number of RunType values return intervals_to_count(intervals); }
对于你的路径,这个worst_case_count接近2GB,你得到一个中止,因为没有从malloc获得那么大的内存.
我看不出任何使用不同参数的方法.任何避免合并clipPaths的东西都必须有所帮助,比如使用Region.Op.REPLACE调用clipPath. Region.Op.INTERSECT也应该失败.
我将集中精力避免在复杂路径上使用复杂路径调用clipPath.
如果它适合您的用例,您可以使用相同的Path对象来设置canvas.clipPath().例如:
Picture picture = new Picture(); Canvas canvas = picture.beginRecording(12240,15840); Path path = new Path(); path.moveTo(3058,12365); path.lineTo(8499,3038); path.lineTo(9494,3619); path.lineTo(4053,12946); path.close(); canvas.clipPath(path); // do stuff with canvas path.moveTo(3065,12332); path.lineTo(4053,12926); path.lineTo(9615,3669); path.lineTo(8628,3075); path.close(); canvas.clipPath(path,Region.Op.REPLACE); // do more stuff with canvas picture.endRecording(); return picture;
由于路径包含以前的图纸,您可以继续更新它.如果这不适用于您的情况,您需要将这些数字缩小或将复杂区域划分为较小的区域,以避免最坏情况下的启发式变得过大.