SIGSEGV en Canvas.clipPath en el segundo clipPath

Tengo un ASUS Nexus 7 con Android 4.2.2 Mi aplicación está generando un SIGSEGV en sk_malloc_flags al ejecutar el siguiente código:

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

El SIGSEGV se informa de la siguiente manera:

  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) 

Obviamente, he simplificado el código a la anterior, la aplicación completa utiliza transformaciones, etc basado en algunos datos de entrada para generar los valores. ¿Son algunas sugerencias sobre cómo solucionar esto sin implementar mi propio código para el recorte en el caso general?

Esto se parece a un caso de esquina mal destinado para la manipulación de clipPath .

 canvas.clipPath(fourthPath); 

Causa una fusión con firstPath anterior, sin embargo, dado que éstas son complejas (no rectangulares), el sistema de formas intenta dibujarlas como scanlines y fusionarlas posteriormente. Para hacer esta fusión, necesita asignar un poco de memoria, pero como se puede ver en SkRegion.cpp , va para el 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); } 

Para sus caminos este worst_case_count se acerca a 2GB y obtendrá un aborto debido a no obtener esa gran memoria de malloc .

No pude ver ninguna forma de salir de él utilizando diferentes parámetros. Cualquier cosa que evite la fusión de clipPath debe ayudar, como llamar a clipPath con Region.Op.REPLACE . Region.Op.INTERSECT debería fallar.

Me concentraría en evitar llamar a clipPath con una ruta compleja en la parte superior de una ruta compleja.

Si se adapta a su caso de uso, puede utilizar el mismo objeto Path para establecer canvas.clipPath() . Por ejemplo:

 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; 

Dado que la path contiene dibujos anteriores, puede continuar actualizándola. Si esto no es aplicable a su caso, usted necesita hacer esos números más pequeños o dividir sus regiones complejas en más pequeñas para evitar que la worst case heuristic sea ​​demasiado grande.

Ok, déjame poner esto en una respuesta, ya que parece bastante lógico para mí:

Para ver si el problema viene de las llamadas clipPath(Path) a clipPath(Path) , intente quitar la llamada al principio o poner canvas.clipPath(fourthPath, Region.Op.REPLACE); En el lugar de canvas.clipPath(fourthPath); Y ver si esa es la causa.

Otra cosa en la que puedo pensar es si las dibujas por separado:

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

Parece que Canvas.clipPath () no es compatible con aceleración de hardware, por lo menos doc dice que: http://developer.android.com/guide/topics/graphics/hardware-accel.html#unsupported

La única solución que me viene a la mente es desactivar la aceleración de hardware.

Puedes hacerlo en:

  • Nivel de aplicación
    <application android:hardwareAccelerated="true" ...>
    En manifiesto

  • Nivel de actividad
    android:hardwareAccelerated="false"
    Para la actividad en manifiesto

  • Nivel de visualización
    view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    Para una vista individual en tiempo de ejecución

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

FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.