在第二个clipPath的Canvas.clipPath中的SIGSEGV

我有一个运行Android 4.2.2的ASUS 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) 

我显然已经简化了上面显示的代码,完整的应用程序使用基于某些input数据的变换等来生成值。 他们有什么build议,如何解决这个问题,而不是在一般情况下执行我自己的裁剪代码?

Solutions Collecting From Web of "在第二个clipPath的Canvas.clipPath中的SIGSEGV"

这看起来像clipPath处理不幸的angular落情况。

 canvas.clipPath(fourthPath); 

导致与以前的firstPath合并,但是因为这些是复杂的(非矩形)形状系统试图将它们绘制为scanlines并在之后进行合并。 为了进行合并,需要分配一些内存,但正如您在SkRegion.cpp中所看到的那样 ,这是heuristic worst case

 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); } 

对于你的path,这个worst_case_count变得接近2GB,并且由于没有从malloc获取那么大的内存而导致中止。

我看不出任何方式使用不同的参数。 避免合并clipPath的任何东西都必须提供帮助,例如使用Region.Op.REPLACE调用Region.Op.REPLACERegion.Op.INTERSECT应该失败。

我将专注于避免在复杂path上使用复杂path调用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; 

由于path包含以前的图纸,您可以继续更新它。 如果这不适用于您的案例,您可能需要将这些数字缩小或将复杂区域划分为较小的区域,以避免worst case heuristic变得过大。

好吧,让我把这个答案,因为它对我来说看起来很合乎逻辑:

要查看问题是否来自clipPath(Path)的后续调用,请尝试先删除调用或将canvas.clipPath(fourthPath, Region.Op.REPLACE);canvas.clipPath(fourthPath); 看看是不是原因

我能想到的另一件事是,如果你分别绘制它们:

 Picture picture = new Picture(); Canvas canvas = picture.beginRecording(12240, 15840); canvas.clipPath(firstPath); picture.endRecording(); canvas = picture.beginRecording(12240, 15840); canvas.clipPath(fourthPath); picture.endRecording(); 

它看起来像Canvas.clipPath()不支持硬件加速,至less文档说: http : //developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported

我想到的唯一解决方法是closures硬件加速。

你可以这样做:

  • 应用级别
    <application android:hardwareAccelerated="true" ...>
    在清单中

  • 活动水平
    android:hardwareAccelerated="false"
    在清单中的活动

  • 查看级别
    view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    在运行时为单个视图

文档:
http://developer.android.com/guide/topics/graphics/hardware-accel.html#controlling