[gs-cvs] rev 8510 - trunk/gs/src
leonardo at ghostscript.com
leonardo at ghostscript.com
Mon Jan 28 15:02:59 PST 2008
Author: leonardo
Date: 2008-01-28 15:02:59 -0800 (Mon, 28 Jan 2008)
New Revision: 8510
Modified:
trunk/gs/src/gsptype2.c
trunk/gs/src/gsptype2.h
trunk/gs/src/gxfill.c
Log:
Fix (graphics) : Optimize filling a path with a shading color.
DETAILS :
Bug 688970 "(shadings) Optimize filling a path with a shading color".
When filling a path with a shading color, the old code
first intersects the the clipping path with the path,
then intersects the result with the shading BBox.
However the intermediate result frequently appears to be
a big list of rectangles, so the second intersection is slow.
This patch accounts that the clipping path and shading BBox
frequently are rectangles, which are easier to intersect with
no converting to paths. Also the shading box is always a quadrangle,
so intersecting it early gives a smaller intermediate result.
Therefore we first intersect the clipping path with the shading BBox,
then with the path.
This patch keeps the old code within #if #endif
until the full regression testing is passed on the server.
Also would like to eliminate the old complicated function
gx_dc_pattern2_clip_with_bbox, which is still called from elswhere.
EXPECTED DIFFERENCES :
None.
Modified: trunk/gs/src/gsptype2.c
===================================================================
--- trunk/gs/src/gsptype2.c 2008-01-28 10:31:45 UTC (rev 8509)
+++ trunk/gs/src/gsptype2.c 2008-01-28 23:02:59 UTC (rev 8510)
@@ -352,6 +352,67 @@
return 0;
}
+#if !SHADING_INTERSECT_CPATH_WITH_PATH_FIRST
+int
+gx_dc_pattern2_clip_with_bbox_simple(const gx_device_color * pdevc, gx_device * pdev,
+ gx_clip_path *cpath_local)
+{
+ int code = 0;
+
+ if (gx_dc_is_pattern2_color(pdevc) && gx_dc_pattern2_color_has_bbox(pdevc) &&
+ (*dev_proc(pdev, pattern_manage))(pdev, gs_no_id, NULL, pattern_manage__shading_area) == 0) {
+ gs_pattern2_instance_t *pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
+ gx_path box_path;
+ gs_memory_t *mem = cpath_local->path.memory;
+
+ gx_path_init_local(&box_path, mem);
+ code = gx_dc_shading_path_add_box(&box_path, pdevc);
+ if (code == gs_error_limitcheck) {
+ /* Ignore huge BBox - bug 689027. */
+ code = 0;
+ } else if (code >= 0) {
+ code = gx_cpath_intersect(cpath_local, &box_path, gx_rule_winding_number, (gs_imager_state *)pinst->saved);
+ }
+ gx_path_free(&box_path, "gx_default_fill_path(path_bbox)");
+ }
+ return code;
+}
+/* Check whether color is a shading with BBox. */
+int
+gx_dc_pattern2_is_rectangular_cell(const gx_device_color * pdevc, gx_device * pdev, gs_fixed_rect *rect)
+{
+ if (gx_dc_is_pattern2_color(pdevc) && gx_dc_pattern2_color_has_bbox(pdevc) &&
+ (*dev_proc(pdev, pattern_manage))(pdev, gs_no_id, NULL, pattern_manage__shading_area) == 0) {
+ gs_pattern2_instance_t *pinst = (gs_pattern2_instance_t *)pdevc->ccolor.pattern;
+ const gs_shading_t *psh = pinst->template.Shading;
+ gs_fixed_point p, q;
+
+ if (is_xxyy(&ctm_only(pinst->saved)))
+ if (psh->params.have_BBox) {
+ int code = gs_point_transform2fixed(&pinst->saved->ctm,
+ psh->params.BBox.p.x, psh->params.BBox.p.y, &p);
+ if (code < 0)
+ return code;
+ code = gs_point_transform2fixed(&pinst->saved->ctm,
+ psh->params.BBox.q.x, psh->params.BBox.q.y, &q);
+ if (code < 0)
+ return code;
+ if (p.x > q.x) {
+ p.x ^= q.x; q.x ^= p.x; p.x ^= q.x;
+ }
+ if (p.y > q.y) {
+ p.y ^= q.y; q.y ^= p.y; p.y ^= q.y;
+ }
+ rect->p = p;
+ rect->q = q;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#endif
+
/* Get a shading color space. */
const gs_color_space *
gx_dc_pattern2_get_color_space(const gx_device_color * pdevc)
Modified: trunk/gs/src/gsptype2.h
===================================================================
--- trunk/gs/src/gsptype2.h 2008-01-28 10:31:45 UTC (rev 8509)
+++ trunk/gs/src/gsptype2.h 2008-01-28 23:02:59 UTC (rev 8510)
@@ -110,9 +110,17 @@
/* Checks whether a PatternType 2 has a shading BBox. */
int gx_dc_pattern2_color_has_bbox(const gx_device_color * pdevc);
+#define SHADING_INTERSECT_CPATH_WITH_PATH_FIRST 0
+
/* Intersect a clipping path a shading BBox. */
int gx_dc_pattern2_clip_with_bbox(const gx_device_color * pdevc, gx_device * pdev,
gx_clip_path *cpath_local, const gx_clip_path **cpath1);
+#if !SHADING_INTERSECT_CPATH_WITH_PATH_FIRST
+int gx_dc_pattern2_clip_with_bbox_simple(const gx_device_color * pdevc, gx_device * pdev,
+ gx_clip_path *cpath);
+/* Check whether color is a shading with BBox. */
+int gx_dc_pattern2_is_rectangular_cell(const gx_device_color * pdevc, gx_device * pdev, gs_fixed_rect *rect);
+#endif
/* Get a shading color space. */
const gs_color_space *gx_dc_pattern2_get_color_space(const gx_device_color * pdevc);
Modified: trunk/gs/src/gxfill.c
===================================================================
--- trunk/gs/src/gxfill.c 2008-01-28 10:31:45 UTC (rev 8509)
+++ trunk/gs/src/gxfill.c 2008-01-28 23:02:59 UTC (rev 8510)
@@ -598,10 +598,12 @@
/* We need a single clipping path here, because shadings and
halftones don't take 2 paths. Compute the clipping path intersection.
*/
- gx_clip_path cpath_intersection, cpath_with_shading_bbox;
- const gx_clip_path *pcpath1, *pcpath2;
gs_imager_state *pis_noconst = (gs_imager_state *)pis; /* Break const. */
+# if SHADING_INTERSECT_CPATH_WITH_PATH_FIRST
+ const gx_clip_path *pcpath1, *pcpath2;
+ gx_clip_path cpath_intersection, cpath_with_shading_bbox;
+
if (ppath != NULL) {
code = gx_cpath_init_local_shared(&cpath_intersection, pcpath, pdev->memory);
if (code < 0)
@@ -621,6 +623,40 @@
pcpath2 = pcpath1;
if (code >= 0)
code = gx_dc_pattern2_clip_with_bbox(pdevc, pdev, &cpath_with_shading_bbox, &pcpath1);
+# else
+ gx_clip_path cpath_intersection;
+ gx_clip_path *pcpath1 = &cpath_intersection;
+ const gs_fixed_rect *pcbox = (pcpath == NULL ? NULL : cpath_is_rectangle(pcpath));
+ gs_fixed_rect shading_rect;
+ int shading_rect_code = gx_dc_pattern2_is_rectangular_cell(pdevc, pdev, &shading_rect);
+ gs_fixed_rect clip_box;
+
+ if (shading_rect_code < 0)
+ return shading_rect_code;
+ if (shading_rect_code != 0 && (pcpath == NULL || pcbox != NULL)) {
+ if (pcbox != NULL)
+ clip_box = *pcbox;
+ else
+ (*dev_proc(pdev, get_clipping_box)) (pdev, &clip_box);
+ rect_intersect(clip_box, shading_rect);
+ code = gx_cpath_from_rectangle(&cpath_intersection, &clip_box);
+ } else if (pcpath != NULL) {
+ /* either *pcpath is not a rectangle, or shading cell is not a rectangle. */
+ code = gx_cpath_init_local_shared(&cpath_intersection, pcpath, pdev->memory);
+ if (code < 0)
+ return code;
+ if (gx_dc_is_pattern2_color(pdevc))
+ code = gx_dc_pattern2_clip_with_bbox_simple(pdevc, pdev, &cpath_intersection);
+ } else {
+ /* Happens with a pattern1 color. */
+ (*dev_proc(pdev, get_clipping_box)) (pdev, &clip_box);
+ gx_cpath_init_local(&cpath_intersection, ppath->memory);
+ code = gx_cpath_from_rectangle(&cpath_intersection, &clip_box);
+ }
+ if (ppath != NULL && code >= 0)
+ code = gx_cpath_intersect_with_params(&cpath_intersection, ppath, params->rule,
+ pis_noconst, params);
+# endif
/* Do fill : */
if (code >= 0) {
gs_fixed_rect clip_box;
@@ -654,10 +690,14 @@
cb.p.x, cb.p.y, cb.q.x - cb.p.x, cb.q.y - cb.p.y,
dev, pis->log_op, rs);
}
+# if SHADING_INTERSECT_CPATH_WITH_PATH_FIRST
if (ppath != NULL)
gx_cpath_free(&cpath_intersection, "shading_fill_cpath_intersection");
if (pcpath1 != pcpath2)
gx_cpath_free(&cpath_with_shading_bbox, "shading_fill_cpath_intersection");
+# else
+ gx_cpath_free(&cpath_intersection, "shading_fill_cpath_intersection");
+# endif
} else {
bool got_dc = false;
vd_save;
More information about the gs-cvs
mailing list