summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/gdevdrop.c429
-rw-r--r--base/gdevmem.h22
2 files changed, 450 insertions, 1 deletions
diff --git a/base/gdevdrop.c b/base/gdevdrop.c
index 7f70f4265..599f1740d 100644
--- a/base/gdevdrop.c
+++ b/base/gdevdrop.c
@@ -1013,3 +1013,432 @@ gs_transparent_rop(gs_logical_operation_t lop)
1013#undef MPo 1013#undef MPo
1014 return (rop & mask) | (rop3_D & ~mask); 1014 return (rop & mask) | (rop3_D & ~mask);
1015} 1015}
1016
1017typedef enum
1018{
1019 transform_pixel_region_portrait,
1020 transform_pixel_region_landscape,
1021 transform_pixel_region_skew
1022} transform_pixel_region_posture;
1023
1024typedef struct mem_transform_pixel_region_state_s mem_transform_pixel_region_state_t;
1025
1026typedef int (mem_transform_pixel_region_render_fn)(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs);
1027
1028struct mem_transform_pixel_region_state_s
1029{
1030 gs_memory_t *mem;
1031 gx_dda_fixed_point pixels;
1032 gx_dda_fixed_point rows;
1033 gs_int_rect clip;
1034 int w;
1035 int h;
1036 int spp;
1037 transform_pixel_region_posture posture;
1038 mem_transform_pixel_region_render_fn *render;
1039 void *passthru;
1040};
1041
1042static void
1043get_portrait_y_extent(mem_transform_pixel_region_state_t *state, int *iy, int *ih)
1044{
1045 fixed y0, y1;
1046 gx_dda_fixed row = state->rows.y;
1047
1048 y0 = dda_current(row);
1049 dda_next(row);
1050 y1 = dda_current(row);
1051
1052 if (y1 < y0) {
1053 fixed t = y1; y1 = y0; y0 = t;
1054 }
1055
1056 *iy = fixed2int_pixround_perfect(y0);
1057 *ih = fixed2int_pixround_perfect(y1) - *iy;
1058}
1059
1060static void
1061get_landscape_x_extent(mem_transform_pixel_region_state_t *state, int *ix, int *iw)
1062{
1063 fixed x0, x1;
1064 gx_dda_fixed row = state->rows.x;
1065
1066 x0 = dda_current(row);
1067 dda_next(row);
1068 x1 = dda_current(row);
1069
1070 if (x1 < x0) {
1071 fixed t = x1; x1 = x0; x0 = t;
1072 }
1073
1074 *ix = fixed2int_pixround_perfect(x0);
1075 *iw = fixed2int_pixround_perfect(x1) - *ix;
1076}
1077
1078static int
1079mem_transform_pixel_region_render_portrait(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
1080{
1081 gx_device_memory *mdev = (gx_device_memory *)dev;
1082 gx_dda_fixed_point pnext;
1083 int vci, vdi;
1084 int irun; /* int x/rrun */
1085 int w = state->w;
1086 int h = state->h;
1087 int spp = state->spp;
1088 const byte *data = buffer[0] + data_x * spp;
1089 const byte *bufend = NULL;
1090 int code = 0;
1091 const byte *run;
1092 int k;
1093 gx_color_value *conc = &cmapper->conc[0];
1094 gx_cmapper_fn *mapper = cmapper->set_color;
1095 byte *out;
1096 byte *out_row;
1097 int minx, maxx;
1098
1099 if (h == 0)
1100 return 0;
1101
1102 /* Clip on y */
1103 get_portrait_y_extent(state, &vci, &vdi);
1104 if (vci < state->clip.p.y)
1105 vdi += vci - state->clip.p.y, vci = state->clip.p.y;
1106 if (vci+vdi > state->clip.q.y)
1107 vdi = state->clip.q.y - vci;
1108 if (vdi <= 0)
1109 return 0;
1110
1111 pnext = state->pixels;
1112 irun = fixed2int_var_rounded(dda_current(pnext.x));
1113 dda_translate(pnext.x, (-fixed_epsilon));
1114 if_debug5m('b', dev->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n",
1115 vci, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y)));
1116
1117 minx = state->clip.p.x;
1118 maxx = state->clip.q.x;
1119 out_row = mdev->base + mdev->raster * vci;
1120 bufend = data + w * spp;
1121 while (data < bufend) {
1122 /* Find the length of the next run. It will either end when we hit
1123 * the end of the source data, or when the pixel data differs. */
1124 run = data + spp;
1125 while (1)
1126 {
1127 dda_next(pnext.x);
1128 if (run >= bufend)
1129 break;
1130 if (memcmp(run, data, spp))
1131 break;
1132 run += spp;
1133 }
1134 /* So we have a run of pixels from data to run that are all the same. */
1135 /* This needs to be sped up */
1136 for (k = 0; k < spp; k++) {
1137 conc[k] = gx_color_value_from_byte(data[k]);
1138 }
1139 mapper(cmapper);
1140 /* Fill the region between irun and fixed2int_var_rounded(pnext.x) */
1141 {
1142 int xi = irun;
1143 int wi = (irun = fixed2int_var_rounded(dda_current(pnext.x))) - xi;
1144
1145 if (wi < 0)
1146 xi += wi, wi = -wi;
1147
1148 if (xi < minx)
1149 wi += xi - minx, xi = minx;
1150 if (xi+wi > maxx)
1151 wi = maxx - xi;
1152 if (wi > 0) {
1153 /* assert(color_is_pure(&cmapper->devc)); */
1154 out = out_row;
1155 for (h = vdi; h > 0; h--, out += mdev->raster) {
1156 gx_color_index color = cmapper->devc.colors.pure;
1157 int xii = xi * spp;
1158 int wii = wi;
1159 do {
1160 /* Excuse the double shifts below, that's to stop the
1161 * C compiler complaining if the color index type is
1162 * 32 bits. */
1163 switch(spp)
1164 {
1165 case 8: out[xii++] = ((color>>28)>>28) & 0xff;
1166 case 7: out[xii++] = ((color>>24)>>24) & 0xff;
1167 case 6: out[xii++] = ((color>>24)>>16) & 0xff;
1168 case 5: out[xii++] = ((color>>24)>>8) & 0xff;
1169 case 4: out[xii++] = (color>>24) & 0xff;
1170 case 3: out[xii++] = (color>>16) & 0xff;
1171 case 2: out[xii++] = (color>>8) & 0xff;
1172 case 1: out[xii++] = color & 0xff;
1173 }
1174 } while (--wii != 0);
1175 }
1176 }
1177 }
1178 data = run;
1179 }
1180 return (code < 0 ? code : 1);
1181 /* Save position if error, in case we resume. */
1182}
1183
1184static int
1185mem_transform_pixel_region_render_landscape(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
1186{
1187 gx_device_memory *mdev = (gx_device_memory *)dev;
1188 gx_dda_fixed_point pnext;
1189 int vci, vdi;
1190 int irun; /* int x/rrun */
1191 int w = state->w;
1192 int h = state->h;
1193 int spp = state->spp;
1194 const byte *data = buffer[0] + data_x * spp;
1195 const byte *bufend = NULL;
1196 int code = 0;
1197 const byte *run;
1198 int k;
1199 gx_color_value *conc = &cmapper->conc[0];
1200 gx_cmapper_fn *mapper = cmapper->set_color;
1201 byte *out;
1202 byte *out_row;
1203 int miny, maxy;
1204
1205 if (h == 0)
1206 return 0;
1207
1208 /* Clip on x */
1209 get_landscape_x_extent(state, &vci, &vdi);
1210 if (vci < state->clip.p.x)
1211 vdi += vci - state->clip.p.x, vci = state->clip.p.x;
1212 if (vci+vdi > state->clip.q.x)
1213 vdi = state->clip.q.x - vci;
1214 if (vdi <= 0)
1215 return 0;
1216
1217 pnext = state->pixels;
1218 irun = fixed2int_var_rounded(dda_current(pnext.y));
1219 dda_translate(pnext.x, (-fixed_epsilon));
1220 if_debug5m('b', dev->memory, "[b]y=%d data_x=%d w=%d xt=%f yt=%f\n",
1221 vci, data_x, w, fixed2float(dda_current(pnext.x)), fixed2float(dda_current(pnext.y)));
1222
1223 miny = state->clip.p.y;
1224 maxy = state->clip.q.y;
1225 out_row = mdev->base + vci * spp;
1226 bufend = data + w * spp;
1227 while (data < bufend) {
1228 /* Find the length of the next run. It will either end when we hit
1229 * the end of the source data, or when the pixel data differs. */
1230 run = data + spp;
1231 while (1)
1232 {
1233 dda_next(pnext.y);
1234 if (run >= bufend)
1235 break;
1236 if (memcmp(run, data, spp))
1237 break;
1238 run += spp;
1239 }
1240 /* So we have a run of pixels from data to run that are all the same. */
1241 /* This needs to be sped up */
1242 for (k = 0; k < spp; k++) {
1243 conc[k] = gx_color_value_from_byte(data[k]);
1244 }
1245 mapper(cmapper);
1246 /* Fill the region between irun and fixed2int_var_rounded(pnext.y) */
1247 { /* 90 degree rotated rectangle */
1248 int yi = irun;
1249 int hi = (irun = fixed2int_var_rounded(dda_current(pnext.y))) - yi;
1250
1251 if (hi < 0)
1252 yi += hi, hi = -hi;
1253
1254 if (yi < miny)
1255 hi += yi - miny, yi = miny;
1256 if (yi+hi > maxy)
1257 hi = maxy - yi;
1258 if (hi > 0) {
1259 /* assert(color_is_pure(&cmapper->devc)); */
1260 out = out_row + mdev->raster * yi;
1261 for (h = hi; h > 0; h--, out += mdev->raster) {
1262 gx_color_index color = cmapper->devc.colors.pure;
1263 int xii = 0;
1264 int wii = vdi;
1265 do {
1266 /* Excuse the double shifts below, that's to stop the
1267 * C compiler complaining if the color index type is
1268 * 32 bits. */
1269 switch(spp)
1270 {
1271 case 8: out[xii++] = ((color>>28)>>28) & 0xff;
1272 case 7: out[xii++] = ((color>>24)>>24) & 0xff;
1273 case 6: out[xii++] = ((color>>24)>>16) & 0xff;
1274 case 5: out[xii++] = ((color>>24)>>8) & 0xff;
1275 case 4: out[xii++] = (color>>24) & 0xff;
1276 case 3: out[xii++] = (color>>16) & 0xff;
1277 case 2: out[xii++] = (color>>8) & 0xff;
1278 case 1: out[xii++] = color & 0xff;
1279 }
1280 } while (--wii != 0);
1281 }
1282 }
1283 }
1284 if (code < 0)
1285 goto err;
1286 data = run;
1287 }
1288 return (code < 0 ? code : 1);
1289 /* Save position if error, in case we resume. */
1290err:
1291 buffer[0] = run;
1292 return code;
1293}
1294
1295static int
1296mem_transform_pixel_region_begin(gx_device *dev, int w, int h, int spp,
1297 const gx_dda_fixed_point *pixels, const gx_dda_fixed_point *rows,
1298 const gs_int_rect *clip, transform_pixel_region_posture posture,
1299 mem_transform_pixel_region_state_t **statep)
1300{
1301 mem_transform_pixel_region_state_t *state;
1302 gs_memory_t *mem = dev->memory->non_gc_memory;
1303 *statep = state = (mem_transform_pixel_region_state_t *)gs_alloc_bytes(mem, sizeof(mem_transform_pixel_region_state_t), "mem_transform_pixel_region_state_t");
1304 if (state == NULL)
1305 return gs_error_VMerror;
1306 state->mem = mem;
1307 state->rows = *rows;
1308 state->pixels = *pixels;
1309 state->clip = *clip;
1310 if (state->clip.p.x < 0)
1311 state->clip.p.x = 0;
1312 if (state->clip.q.x > dev->width)
1313 state->clip.q.x = dev->width;
1314 if (state->clip.p.y < 0)
1315 state->clip.p.y = 0;
1316 if (state->clip.q.y > dev->height)
1317 state->clip.q.y = dev->height;
1318 state->w = w;
1319 state->h = h;
1320 state->spp = spp;
1321 state->posture = posture;
1322
1323 if (state->posture == transform_pixel_region_portrait)
1324 state->render = mem_transform_pixel_region_render_portrait;
1325 else
1326 state->render = mem_transform_pixel_region_render_landscape;
1327
1328 return 0;
1329}
1330
1331static void
1332step_to_next_line(mem_transform_pixel_region_state_t *state)
1333{
1334 fixed x = dda_current(state->rows.x);
1335 fixed y = dda_current(state->rows.y);
1336 dda_next(state->rows.x);
1337 dda_next(state->rows.y);
1338 x = dda_current(state->rows.x) - x;
1339 y = dda_current(state->rows.y) - y;
1340 dda_translate(state->pixels.x, x);
1341 dda_translate(state->pixels.y, y);
1342}
1343
1344static int
1345mem_transform_pixel_region_data_needed(gx_device *dev, mem_transform_pixel_region_state_t *state)
1346{
1347 if (state->posture == transform_pixel_region_portrait) {
1348 int iy, ih;
1349
1350 get_portrait_y_extent(state, &iy, &ih);
1351
1352 if (iy + ih < state->clip.p.y || iy >= state->clip.q.y) {
1353 /* Skip this line. */
1354 step_to_next_line(state);
1355 return 0;
1356 }
1357 } else if (state->posture == transform_pixel_region_landscape) {
1358 int ix, iw;
1359
1360 get_landscape_x_extent(state, &ix, &iw);
1361
1362 if (ix + iw < state->clip.p.x || ix >= state->clip.q.x) {
1363 /* Skip this line. */
1364 step_to_next_line(state);
1365 return 0;
1366 }
1367 }
1368
1369 return 1;
1370}
1371
1372static int
1373mem_transform_pixel_region_process_data(gx_device *dev, mem_transform_pixel_region_state_t *state, const unsigned char **buffer, int data_x, gx_cmapper_t *cmapper, const gs_gstate *pgs)
1374{
1375 int ret = state->render(dev, state, buffer, data_x, cmapper, pgs);
1376 step_to_next_line(state);
1377 return ret;
1378}
1379
1380static int
1381mem_transform_pixel_region_end(gx_device *dev, mem_transform_pixel_region_state_t *state)
1382{
1383 if (state)
1384 gs_free_object(state->mem->non_gc_memory, state, "mem_transform_pixel_region_state_t");
1385 return 0;
1386}
1387
1388int mem_transform_pixel_region(gx_device *dev, transform_pixel_region_reason reason, transform_pixel_region_data *data)
1389{
1390 mem_transform_pixel_region_state_t *state = (mem_transform_pixel_region_state_t *)data->state;
1391 transform_pixel_region_posture posture;
1392
1393 /* Pass through */
1394 if (reason == transform_pixel_region_begin) {
1395 const gx_dda_fixed_point *rows = data->u.init.rows;
1396 const gx_dda_fixed_point *pixels = data->u.init.pixels;
1397 if (rows->x.step.dQ == 0 && rows->x.step.dR == 0 && pixels->y.step.dQ == 0 && pixels->y.step.dR == 0)
1398 posture = transform_pixel_region_portrait;
1399 else if (rows->y.step.dQ == 0 && rows->y.step.dR == 0 && pixels->x.step.dQ == 0 && pixels->x.step.dR == 0)
1400 posture = transform_pixel_region_landscape;
1401 else
1402 posture = transform_pixel_region_skew;
1403
1404 if (posture == transform_pixel_region_skew || dev->color_info.depth != data->u.init.spp*8 || data->u.init.lop != 0xf0) {
1405 mem_transform_pixel_region_state_t *state = (mem_transform_pixel_region_state_t *)gs_alloc_bytes(dev->memory->non_gc_memory, sizeof(mem_transform_pixel_region_state_t), "mem_transform_pixel_region_state_t");
1406 if (state == NULL)
1407 return gs_error_VMerror;
1408 state->render = NULL;
1409 if (gx_default_transform_pixel_region(dev, transform_pixel_region_begin, data) < 0) {
1410 gs_free_object(dev->memory->non_gc_memory, state, "mem_transform_pixel_region_state_t");
1411 return gs_error_VMerror;
1412 }
1413 state->passthru = data->state;
1414 data->state = state;
1415 return 0;
1416 }
1417 } else if (state->render == NULL) {
1418 int ret;
1419 data->state = state->passthru;
1420 ret = gx_default_transform_pixel_region(dev, reason, data);
1421 data->state = state;
1422 if (reason == transform_pixel_region_end) {
1423 gs_free_object(dev->memory->non_gc_memory, state, "mem_transform_pixel_region_state_t");
1424 data->state = NULL;
1425 }
1426 return ret;
1427 }
1428
1429 /* We can handle this case natively */
1430 switch(reason)
1431 {
1432 case transform_pixel_region_begin:
1433 return mem_transform_pixel_region_begin(dev, data->u.init.w, data->u.init.h, data->u.init.spp, data->u.init.pixels, data->u.init.rows, data->u.init.clip, posture, (mem_transform_pixel_region_state_t **)&data->state);
1434 case transform_pixel_region_data_needed:
1435 return mem_transform_pixel_region_data_needed(dev, state);
1436 case transform_pixel_region_process_data:
1437 return mem_transform_pixel_region_process_data(dev, state, data->u.process_data.buffer, data->u.process_data.data_x, data->u.process_data.cmapper, data->u.process_data.pgs);
1438 case transform_pixel_region_end:
1439 data->state = NULL;
1440 return mem_transform_pixel_region_end(dev, state);
1441 default:
1442 return gs_error_unknownerror;
1443 }
1444}
diff --git a/base/gdevmem.h b/base/gdevmem.h
index 262c9d109..15174571e 100644
--- a/base/gdevmem.h
+++ b/base/gdevmem.h
@@ -102,6 +102,7 @@ dev_proc_map_color_rgb(mem_mapped_map_color_rgb);
102/* Default implementations */ 102/* Default implementations */
103dev_proc_strip_copy_rop(mem_default_strip_copy_rop); 103dev_proc_strip_copy_rop(mem_default_strip_copy_rop);
104dev_proc_strip_copy_rop2(mem_default_strip_copy_rop2); 104dev_proc_strip_copy_rop2(mem_default_strip_copy_rop2);
105dev_proc_transform_pixel_region(mem_transform_pixel_region);
105 106
106/* 107/*
107 * Macro for generating the device descriptor. 108 * Macro for generating the device descriptor.
@@ -182,7 +183,26 @@ dev_proc_strip_copy_rop2(mem_default_strip_copy_rop2);
182 NULL, /* encode_color */\ 183 NULL, /* encode_color */\
183 NULL, /* decode_color */\ 184 NULL, /* decode_color */\
184 NULL, /* pattern_manage */\ 185 NULL, /* pattern_manage */\
185 fill_rectangle_hl_color /* fill_rectangle_hl_color */\ 186 fill_rectangle_hl_color, /* fill_rectangle_hl_color */\
187 NULL, /* include_color_space */\
188 NULL, /* fill_linear_color_scanline */\
189 NULL, /* fill_linear_color_trapezoid */\
190 NULL, /* fill_linear_color_triangle */\
191 NULL, /* update_spot_equivalent_colors */\
192 NULL, /* ret_devn_params */\
193 NULL, /* fillpage */\
194 NULL, /* push_transparency_state */\
195 NULL, /* pop_transparency_state */\
196 NULL, /* put_image */\
197 NULL, /* dev_spec_op */\
198 NULL, /* copy_planes */\
199 NULL, /* get_profile */\
200 NULL, /* set_graphics_type_tag */\
201 NULL, /* strip_copy_rop2 */\
202 NULL, /* strip_tile_rect_devn */\
203 NULL, /* copy_alpha_hl_color */\
204 NULL, /* process_page */\
205 mem_transform_pixel_region\
186 },\ 206 },\
187 0, /* target */\ 207 0, /* target */\
188 mem_device_init_private /* see gxdevmem.h */\ 208 mem_device_init_private /* see gxdevmem.h */\