Skip to content

Commit baaf1f4

Browse files
committed
Merge pull request #1816 from mdehoon/master
Avoid macosx backend slowdown; issue 1563
2 parents 5a7cb7f + 8ec89ce commit baaf1f4

File tree

1 file changed

+107
-76
lines changed

1 file changed

+107
-76
lines changed

src/_macosx.m

Lines changed: 107 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -240,11 +240,15 @@ static void _dealloc_atsui(void)
240240
}
241241
#endif
242242

243-
static int _draw_path(CGContextRef cr, void* iterator)
243+
static int _draw_path(CGContextRef cr, void* iterator, int nmax)
244244
{
245245
double x1, y1, x2, y2, x3, y3;
246+
static unsigned code = STOP;
247+
static double xs, ys;
248+
CGPoint current;
246249
int n = 0;
247-
unsigned code;
250+
251+
if (code == MOVETO) CGContextMoveToPoint(cr, xs, ys);
248252

249253
while (true)
250254
{
@@ -261,7 +265,6 @@ static int _draw_path(CGContextRef cr, void* iterator)
261265
else if (code == MOVETO)
262266
{
263267
CGContextMoveToPoint(cr, x1, y1);
264-
n++;
265268
}
266269
else if (code==LINETO)
267270
{
@@ -270,31 +273,50 @@ static int _draw_path(CGContextRef cr, void* iterator)
270273
}
271274
else if (code==CURVE3)
272275
{
273-
get_vertex(iterator, &x2, &y2);
274-
CGContextAddQuadCurveToPoint(cr, x1, y1, x2, y2);
276+
get_vertex(iterator, &xs, &ys);
277+
CGContextAddQuadCurveToPoint(cr, x1, y1, xs, ys);
275278
n+=2;
276279
}
277280
else if (code==CURVE4)
278281
{
279282
get_vertex(iterator, &x2, &y2);
280-
get_vertex(iterator, &x3, &y3);
281-
CGContextAddCurveToPoint(cr, x1, y1, x2, y2, x3, y3);
283+
get_vertex(iterator, &xs, &ys);
284+
CGContextAddCurveToPoint(cr, x1, y1, x2, y2, xs, ys);
282285
n+=3;
283286
}
287+
if (n >= nmax)
288+
{
289+
switch (code)
290+
{
291+
case MOVETO:
292+
case LINETO:
293+
xs = x1;
294+
ys = y1;
295+
break;
296+
case CLOSEPOLY:
297+
current = CGContextGetPathCurrentPoint(cr);
298+
xs = current.x;
299+
ys = current.y;
300+
break;
301+
/* nothing needed for CURVE3, CURVE4 */
302+
}
303+
code = MOVETO;
304+
return -n;
305+
}
284306
}
285307
return n;
286308
}
287309

288310
static void _draw_hatch(void *info, CGContextRef cr)
289311
{
312+
int n;
290313
PyObject* hatchpath = (PyObject*)info;
291314
PyObject* transform;
292315
int nd = 2;
293316
npy_intp dims[2] = {3, 3};
294317
int typenum = NPY_DOUBLE;
295318
double data[9] = {HATCH_SIZE, 0, 0, 0, HATCH_SIZE, 0, 0, 0, 1};
296319
double rect[4] = { 0.0, 0.0, HATCH_SIZE, HATCH_SIZE};
297-
int n;
298320
transform = PyArray_SimpleNewFromData(nd, dims, typenum, data);
299321
if (!transform)
300322
{
@@ -320,7 +342,7 @@ static void _draw_hatch(void *info, CGContextRef cr)
320342
PyGILState_Release(gstate);
321343
return;
322344
}
323-
n = _draw_path(cr, iterator);
345+
n = _draw_path(cr, iterator, INT_MAX);
324346
free_path_iterator(iterator);
325347
if (n==0) return;
326348
CGContextSetLineWidth(cr, 1.0);
@@ -702,7 +724,7 @@ static int _get_snap(GraphicsContext* self, enum e_snap_mode* mode)
702724
"set_clip_path: failed to obtain path iterator for clipping");
703725
return NULL;
704726
}
705-
n = _draw_path(cr, iterator);
727+
n = _draw_path(cr, iterator, INT_MAX);
706728
free_path_iterator(iterator);
707729

708730
if (n > 0) CGContextClip(cr);
@@ -952,89 +974,98 @@ static int _get_snap(GraphicsContext* self, enum e_snap_mode* mode)
952974
"draw_path: failed to obtain path iterator");
953975
return NULL;
954976
}
955-
n = _draw_path(cr, iterator);
956-
free_path_iterator(iterator);
957977

958-
if (n > 0)
978+
if(rgbFace)
959979
{
960-
PyObject* hatchpath;
961-
if(rgbFace)
980+
float r, g, b;
981+
if (!PyArg_ParseTuple(rgbFace, "fff", &r, &g, &b))
982+
return NULL;
983+
n = _draw_path(cr, iterator, INT_MAX);
984+
if (n > 0)
962985
{
963-
float r, g, b;
964-
if (!PyArg_ParseTuple(rgbFace, "fff", &r, &g, &b))
965-
return NULL;
966986
CGContextSaveGState(cr);
967987
CGContextSetRGBFillColor(cr, r, g, b, 1.0);
968988
CGContextDrawPath(cr, kCGPathFillStroke);
969989
CGContextRestoreGState(cr);
970990
}
971-
else CGContextStrokePath(cr);
991+
}
992+
else
993+
{
994+
const int nmax = 100;
995+
while (true)
996+
{
997+
n = _draw_path(cr, iterator, nmax);
998+
if (n != 0) CGContextStrokePath(cr);
999+
if (n >= 0) break;
1000+
}
1001+
}
1002+
free_path_iterator(iterator);
9721003

973-
hatchpath = PyObject_CallMethod((PyObject*)self, "get_hatch_path", "");
974-
if (!hatchpath)
1004+
PyObject* hatchpath;
1005+
hatchpath = PyObject_CallMethod((PyObject*)self, "get_hatch_path", "");
1006+
if (!hatchpath)
1007+
{
1008+
return NULL;
1009+
}
1010+
else if (hatchpath==Py_None)
1011+
{
1012+
Py_DECREF(hatchpath);
1013+
}
1014+
else
1015+
{
1016+
CGPatternRef pattern;
1017+
CGColorSpaceRef baseSpace;
1018+
CGColorSpaceRef patternSpace;
1019+
static const CGPatternCallbacks callbacks = {0,
1020+
&_draw_hatch,
1021+
&_release_hatch};
1022+
baseSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
1023+
if (!baseSpace)
9751024
{
1025+
Py_DECREF(hatchpath);
1026+
PyErr_SetString(PyExc_RuntimeError,
1027+
"draw_path: CGColorSpaceCreateWithName failed");
9761028
return NULL;
9771029
}
978-
else if (hatchpath==Py_None)
1030+
patternSpace = CGColorSpaceCreatePattern(baseSpace);
1031+
CGColorSpaceRelease(baseSpace);
1032+
if (!patternSpace)
9791033
{
9801034
Py_DECREF(hatchpath);
1035+
PyErr_SetString(PyExc_RuntimeError,
1036+
"draw_path: CGColorSpaceCreatePattern failed");
1037+
return NULL;
9811038
}
982-
else
1039+
CGContextSetFillColorSpace(cr, patternSpace);
1040+
CGColorSpaceRelease(patternSpace);
1041+
1042+
pattern = CGPatternCreate((void*)hatchpath,
1043+
CGRectMake(0, 0, HATCH_SIZE, HATCH_SIZE),
1044+
CGAffineTransformIdentity,
1045+
HATCH_SIZE, HATCH_SIZE,
1046+
kCGPatternTilingNoDistortion,
1047+
false,
1048+
&callbacks);
1049+
CGContextSetFillPattern(cr, pattern, self->color);
1050+
CGPatternRelease(pattern);
1051+
iterator = get_path_iterator(path,
1052+
transform,
1053+
1,
1054+
0,
1055+
rect,
1056+
SNAP_AUTO,
1057+
linewidth,
1058+
0);
1059+
if (!iterator)
9831060
{
984-
CGPatternRef pattern;
985-
CGColorSpaceRef baseSpace;
986-
CGColorSpaceRef patternSpace;
987-
static const CGPatternCallbacks callbacks = {0,
988-
&_draw_hatch,
989-
&_release_hatch};
990-
baseSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
991-
if (!baseSpace)
992-
{
993-
Py_DECREF(hatchpath);
994-
PyErr_SetString(PyExc_RuntimeError,
995-
"draw_path: CGColorSpaceCreateWithName failed");
996-
return NULL;
997-
}
998-
patternSpace = CGColorSpaceCreatePattern(baseSpace);
999-
CGColorSpaceRelease(baseSpace);
1000-
if (!patternSpace)
1001-
{
1002-
Py_DECREF(hatchpath);
1003-
PyErr_SetString(PyExc_RuntimeError,
1004-
"draw_path: CGColorSpaceCreatePattern failed");
1005-
return NULL;
1006-
}
1007-
CGContextSetFillColorSpace(cr, patternSpace);
1008-
CGColorSpaceRelease(patternSpace);
1009-
1010-
pattern = CGPatternCreate((void*)hatchpath,
1011-
CGRectMake(0, 0, HATCH_SIZE, HATCH_SIZE),
1012-
CGAffineTransformIdentity,
1013-
HATCH_SIZE, HATCH_SIZE,
1014-
kCGPatternTilingNoDistortion,
1015-
false,
1016-
&callbacks);
1017-
CGContextSetFillPattern(cr, pattern, self->color);
1018-
CGPatternRelease(pattern);
1019-
iterator = get_path_iterator(path,
1020-
transform,
1021-
1,
1022-
0,
1023-
rect,
1024-
SNAP_AUTO,
1025-
linewidth,
1026-
0);
1027-
if (!iterator)
1028-
{
1029-
Py_DECREF(hatchpath);
1030-
PyErr_SetString(PyExc_RuntimeError,
1031-
"draw_path: failed to obtain path iterator for hatching");
1032-
return NULL;
1033-
}
1034-
n = _draw_path(cr, iterator);
1035-
free_path_iterator(iterator);
1036-
CGContextFillPath(cr);
1061+
Py_DECREF(hatchpath);
1062+
PyErr_SetString(PyExc_RuntimeError,
1063+
"draw_path: failed to obtain path iterator for hatching");
1064+
return NULL;
10371065
}
1066+
n = _draw_path(cr, iterator, INT_MAX);
1067+
free_path_iterator(iterator);
1068+
if (n > 0) CGContextFillPath(cr);
10381069
}
10391070

10401071
Py_INCREF(Py_None);

0 commit comments

Comments
 (0)