home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises. All rights reserved.
-
- This file is part of Aladdin Ghostscript.
-
- Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author
- or distributor accepts any responsibility for the consequences of using it,
- or for whether it serves any particular purpose or works at all, unless he
- or she says so in writing. Refer to the Aladdin Ghostscript Free Public
- License (the "License") for full details.
-
- Every copy of Aladdin Ghostscript must include a copy of the License,
- normally in a plain ASCII text file named PUBLIC. The License grants you
- the right to copy, modify and redistribute Aladdin Ghostscript, but only
- under certain conditions described in the License. Among other things, the
- License requires that the copyright notice and this notice be preserved on
- all copies.
- */
-
- /* gsstate.c */
- /* Miscellaneous graphics state operators for Ghostscript library */
- #include "gx.h"
- #include "memory_.h"
- #include "gserrors.h"
- #include "gsstruct.h"
- #include "gzstate.h"
- #include "gscspace.h"
- #include "gscolor2.h"
- #include "gscoord.h" /* for gs_initmatrix */
- #include "gscie.h"
- #include "gxcmap.h"
- #include "gzht.h"
- #include "gzline.h"
- #include "gzpath.h"
-
- /* Imported values */
- /* The following should include a 'const', but */
- /* the Watcom compiler won't accept it. */
- extern /*const*/ gx_color_map_procs *cmap_procs_default;
-
- /* Forward references */
- private gs_state *alloc_gstate(P3(gs_memory_t *, const gs_state *,
- client_name_t));
- private int alloc_gstate_contents(P1(gs_state *));
- private void free_gstate_contents(P1(gs_state *));
- private void copy_gstate_contents(P2(gs_state *pto, const gs_state *pfrom));
-
- /* The structure for allocating (most of) the contents of a gstate */
- /* all at once. The typedef is in gzstate.c. */
- struct gs_state_contents_s {
- gx_path path;
- gx_clip_path clip_path;
- gx_line_params line_params;
- gs_halftone halftone;
- gx_device_halftone dev_ht;
- gs_color_space color_space;
- gs_client_color ccolor;
- gx_device_color dev_color;
- };
-
- /* Enumerate the pointers in a graphics state, other than the ones */
- /* that point to the gs_state_contents. */
- #define gs_state_do_ptrs(m)\
- m(0,saved) m(1,ht_cache) m(2,contents)\
- m(3,cie_render) m(4,black_generation) m(5,undercolor_removal)\
- m(6,transfer.red) m(7,transfer.green) m(8,transfer.blue)\
- m(9,transfer.gray)\
- m(10,cie_joint_caches) m(11,pattern_cache) m(12,font) m(13,root_font)\
- m(14,show_gstate) /*m(---,device)*/ m(15,client_data)
- #define gs_state_num_ptrs 16
- /* Enumerate the pointers to the gs_state_contents. */
- #define gs_state_do_contents_ptrs(m)\
- m(0,path) m(1,clip_path) m(2,line_params) m(3,halftone) m(4,dev_ht)\
- m(5,color_space) m(6,ccolor) m(7,dev_color)
- #define gs_state_num_contents_ptrs 8
-
- public_st_gstate();
- /* Components of the graphics state */
- gs_private_st_composite(st_gstate_contents, gs_state_contents,
- "gs_state_contents", state_contents_enum_ptrs, state_contents_reloc_ptrs);
- public_st_transfer_map();
- private_st_line_params();
-
- /* GC procedures for gs_state */
- #define gsvptr ((gs_state *)vptr)
- private ENUM_PTRS_BEGIN(gs_state_enum_ptrs) return 0;
- #define e1(i,elt) ENUM_PTR(i,gs_state,elt);
- gs_state_do_ptrs(e1)
- case gs_state_num_ptrs: /* handle device specially */
- *pep = gx_device_enum_ptr(gsvptr->device);
- break;
- #undef e1
- ENUM_PTRS_END
- private RELOC_PTRS_BEGIN(gs_state_reloc_ptrs) {
- byte *cont = (byte *)gsvptr->contents;
- uint reloc;
- #define r1(i,elt) RELOC_PTR(gs_state,elt);
- gs_state_do_ptrs(r1)
- #undef r1
- gsvptr->device = gx_device_reloc_ptr(gsvptr->device, gcst);
- reloc = cont - (byte *)gsvptr->contents;
- #define r1(i,elt)\
- gsvptr->elt = (void *)((byte *)gsvptr->elt - reloc);
- gs_state_do_contents_ptrs(r1)
- #undef r1
- } RELOC_PTRS_END
- #undef gsvptr
-
- /* GC procedures for gs_state_contents */
- #define cptr ((gs_state_contents *)vptr)
- private ENUM_PTRS_BEGIN_PROC(state_contents_enum_ptrs) {
- gs_ptr_type_t ret;
- #define next_comp(np, st, e)\
- if ( index < np ) { ret = (*st.enum_ptrs)(&cptr->e, sizeof(cptr->e), index, pep); goto rx; }\
- index -= np
- #define last_comp(np, st, e)\
- return (*st.enum_ptrs)(&cptr->e, sizeof(cptr->e), index, pep)
- next_comp(st_path_max_ptrs, st_path, path);
- next_comp(st_clip_path_max_ptrs, st_clip_path, clip_path);
- next_comp(st_line_params_max_ptrs, st_line_params, line_params);
- next_comp(st_halftone_max_ptrs, st_halftone, halftone);
- next_comp(st_device_halftone_max_ptrs, st_device_halftone, dev_ht);
- next_comp(st_color_space_max_ptrs, st_color_space, color_space);
- next_comp(st_client_color_max_ptrs, st_client_color, ccolor);
- last_comp(st_device_color_max_ptrs, st_device_color, dev_color);
- #undef next_comp
- rx: if ( ret == 0 )
- { /* A component ran out of pointers early. */
- /* Just return a null so we can keep going. */
- *pep = 0;
- return ptr_struct_type;
- }
- return ret;
- ENUM_PTRS_END_PROC }
- private RELOC_PTRS_BEGIN(state_contents_reloc_ptrs) {
- (*st_path.reloc_ptrs)(&cptr->path, sizeof(gx_path), gcst);
- (*st_clip_path.reloc_ptrs)(&cptr->clip_path, sizeof(gx_clip_path), gcst);
- (*st_line_params.reloc_ptrs)(&cptr->line_params, sizeof(gx_line_params), gcst);
- (*st_halftone.reloc_ptrs)(&cptr->halftone, sizeof(gs_halftone), gcst);
- (*st_device_halftone.reloc_ptrs)(&cptr->dev_ht, sizeof(gx_device_halftone), gcst);
- (*st_color_space.reloc_ptrs)(&cptr->color_space, sizeof(gs_color_space), gcst);
- (*st_client_color.reloc_ptrs)(&cptr->ccolor, sizeof(gs_client_color), gcst);
- (*st_device_color.reloc_ptrs)(&cptr->dev_color, sizeof(gx_device_color), gcst);
- } RELOC_PTRS_END
- #undef cptr
-
- /* ------ Operations on the entire graphics state ------ */
-
- /* Allocate and initialize a graphics state. */
- private float
- null_transfer(const gs_state *pgs, floatp gray)
- { return gray;
- }
- gs_state *
- gs_state_alloc(gs_memory_t *mem)
- { register gs_state *pgs =
- alloc_gstate(mem, (gs_state *)0, "gs_state_alloc");
- if ( pgs == 0 )
- return 0;
- pgs->saved = 0;
- /* Initialize things not covered by initgraphics */
- gx_path_init(pgs->path, mem);
- gx_cpath_init(pgs->clip_path, mem);
- /* The following is a hack for the GC. */
- pgs->clip_path->list.container_offset =
- offset_of(gs_state_contents, clip_path.list);
- pgs->ht_cache = gx_ht_alloc_cache(mem,
- ht_cache_default_max_tiles,
- ht_cache_default_max_bits);
- { /* It would be great if we could use statically initialized */
- /* structures for the levels and bits arrays, */
- /* but that would confuse the GC. */
- uint *levels =
- (uint *)gs_alloc_bytes(mem, sizeof(uint),
- "gs_state_alloc(ht levels)");
- gx_ht_bit *bits =
- (gx_ht_bit *)gs_alloc_bytes(mem, sizeof(gx_ht_bit),
- "gs_state_alloc(ht bits)");
- pgs->dev_ht->order.width = pgs->dev_ht->order.height =
- pgs->dev_ht->order.num_levels =
- pgs->dev_ht->order.num_bits = 1;
- levels[0] = 1;
- pgs->dev_ht->order.levels = levels;
- bits[0].offset = 0;
- bits[0].mask = 0;
- pgs->dev_ht->order.bits = bits;
- pgs->dev_ht->order.cache = 0;
- pgs->dev_ht->components = 0;
- }
- pgs->pattern_cache = 0;
- gs_sethalftonephase(pgs, 0, 0);
- /* Initialize things so that gx_remap_color won't crash. */
- gx_set_black(pgs);
- pgs->overprint = 0;
- pgs->black_generation = 0;
- pgs->undercolor_removal = 0;
- pgs->cmap_procs = cmap_procs_default;
- gs_nulldevice(pgs);
- gs_setalpha(pgs, 1.0);
- gs_settransfer(pgs, null_transfer);
- gs_setflat(pgs, 1.0);
- gs_setstrokeadjust(pgs, 1);
- pgs->font = 0; /* Not right, but acceptable until the */
- /* PostScript code does the first setfont. */
- pgs->root_font = 0; /* ditto */
-
- pgs->in_cachedevice = pgs->in_charpath = 0;
- pgs->show_gstate = 0;
- pgs->level = 0;
- pgs->fill_adjust = float2fixed(0.25);
- pgs->client_data = 0;
- if ( gs_initgraphics(pgs) < 0 )
- { /* Something went very wrong */
- return 0;
- }
- return pgs;
- }
-
- /* Set the client data in a graphics state. */
- /* This should only be done to a newly created state. */
- void
- gs_state_set_client(gs_state *pgs, void *pdata,
- const gs_state_client_procs *pprocs)
- { pgs->client_data = pdata;
- pgs->client_procs = *pprocs;
- }
-
- /* Get the client data from a graphics state. */
- void *
- gs_state_client_data(const gs_state *pgs)
- { return pgs->client_data;
- }
-
- /* Free a graphics state */
- int
- gs_state_free(gs_state *pgs)
- { free_gstate_contents(pgs);
- gs_free_object(pgs->memory, pgs, "gs_state_free");
- return 0;
- }
-
- /* Save the graphics state */
- int
- gs_gsave(gs_state *pgs)
- { gs_state *pnew =
- gs_alloc_struct(pgs->memory, gs_state, &st_gstate, "gs_gsave");
- if ( pnew == 0 )
- return_error(gs_error_VMerror);
- *pnew = *pgs;
- if ( alloc_gstate_contents(pgs) < 0 )
- { *pgs = *pnew; /* undo partial alloc */
- gs_free_object(pgs->memory, pnew, "gs_gsave");
- return_error(gs_error_VMerror);
- }
- copy_gstate_contents(pgs, pnew);
- /* Make pnew, not pgs, have the newly-allocated client data. */
- { void *pdata = pgs->client_data;
- pgs->client_data = pnew->client_data;
- pnew->client_data = pdata;
- }
- pgs->saved = pnew;
- if ( pgs->show_gstate == pgs )
- pgs->show_gstate = pnew->show_gstate = pnew;
- pgs->level++;
- if_debug2('g', "[g]gsave -> 0x%lx, level = %d\n",
- (ulong)pnew, pgs->level);
- return 0;
- }
-
- /* Restore the graphics state. */
- int
- gs_grestore(gs_state *pgs)
- { gs_state *saved = pgs->saved;
- void *pdata = pgs->client_data;
- void *sdata;
- if_debug2('g', "[g]grestore 0x%lx, level was %d\n",
- (ulong)saved, pgs->level);
- if ( !saved ) return gs_gsave(pgs); /* shouldn't happen */
- sdata = saved->client_data;
- if ( saved->pattern_cache == 0 )
- saved->pattern_cache = pgs->pattern_cache;
- /* Swap back the client data pointers. */
- pgs->client_data = sdata;
- saved->client_data = pdata;
- if ( pdata != 0 && sdata != 0 )
- (*pgs->client_procs.copy)(pdata, sdata);
- free_gstate_contents(pgs);
- *pgs = *saved;
- if ( pgs->show_gstate == saved )
- pgs->show_gstate = pgs;
- gs_free_object(pgs->memory, saved, "gs_grestore");
- return (pgs->saved == 0 ? gs_gsave(pgs) : 0);
- }
-
- /* Restore to the bottommost graphics state. Also clear */
- /* the halftone caches, so stale pointers don't survive a restore. */
- int
- gs_grestoreall(gs_state *pgs)
- { int code;
- if ( !pgs->saved ) /* shouldn't happen */
- return gs_gsave(pgs);
- while ( pgs->saved->saved )
- { int code = gs_grestore(pgs);
- if ( code < 0 )
- return code;
- }
- code = gs_grestore(pgs);
- if ( code < 0 )
- return code;
- gx_ht_clear_cache(pgs->ht_cache);
- return code;
- }
-
- /* Allocate and return a new graphics state. */
- gs_state *
- gs_gstate(gs_state *pgs)
- { gs_state *pnew = alloc_gstate(pgs->memory, pgs, "gs_gstate");
- if ( pnew == 0 ) return 0;
- copy_gstate_contents(pnew, pgs);
- pnew->saved = 0;
- return pnew;
- }
-
- /* Copy one previously allocated graphics state to another. */
- int
- gs_copygstate(gs_state *pto, const gs_state *pfrom)
- { /* This is the same as currentgstate. */
- return gs_currentgstate(pto, pfrom);
- }
-
- /* Copy the current graphics state to a previously allocated one. */
- int
- gs_currentgstate(gs_state *pto, const gs_state *pgs)
- { /* We have to copy both the scalar and composite parts */
- /* of the state. */
- gs_state sgs;
- sgs = *pto;
- *pto = *pgs;
- /* Put back the composite part pointers. */
- #define gcopy(element)\
- pto->element = sgs.element
- gcopy(contents);
- if ( pto->pattern_cache == 0 )
- gcopy(pattern_cache);
- gcopy(path);
- gcopy(clip_path);
- gcopy(line_params);
- gcopy(halftone);
- gcopy(dev_ht);
- gcopy(color_space);
- gcopy(ccolor);
- gcopy(dev_color);
- gcopy(cie_render);
- gcopy(black_generation);
- gcopy(undercolor_removal);
- gcopy(transfer.red);
- gcopy(transfer.green);
- gcopy(transfer.blue);
- gcopy(transfer.gray);
- gcopy(device);
- gcopy(client_data);
- #undef gcopy
- copy_gstate_contents(pto, pgs);
- return 0;
- }
-
- /* Restore the current graphics state from a previously allocated one. */
- int
- gs_setgstate(gs_state *pgs, const gs_state *pfrom)
- { /* The implementation is the same as currentgstate, */
- /* except we must preserve the saved pointer and the level. */
- gs_state *saved = pgs->saved;
- int level = pgs->level;
- int code = gs_currentgstate(pgs, pfrom);
- if ( code < 0 ) return code;
- pgs->saved = saved;
- pgs->level = level;
- return 0;
- }
-
- /* Get the allocator pointer of a graphics state. */
- /* This is provided only for the interpreter. */
- gs_memory_t *
- gs_state_memory(const gs_state *pgs)
- { return pgs->memory;
- }
-
- /* Get the saved pointer of the graphics state. */
- /* This is provided only for Level 2 grestore. */
- gs_state *
- gs_state_saved(const gs_state *pgs)
- { return pgs->saved;
- }
-
- /* Swap the saved pointer of the graphics state. */
- /* This is provided only for save/restore. */
- gs_state *
- gs_state_swap_saved(gs_state *pgs, gs_state *new_saved)
- { gs_state *saved = pgs->saved;
- pgs->saved = new_saved;
- return saved;
- }
-
- /* Swap the memory pointer of the graphics state. */
- /* This is provided only for the interpreter. */
- gs_memory_t *
- gs_state_swap_memory(gs_state *pgs, gs_memory_t *mem)
- { gs_memory_t *memory = pgs->memory;
- pgs->memory = mem;
- return memory;
- }
-
- /* ------ Operations on components ------ */
-
- /* Reset most of the graphics state */
- int
- gs_initgraphics(register gs_state *pgs)
- { int code;
- gs_initmatrix(pgs);
- if ( (code = gs_newpath(pgs)) < 0 ||
- (code = gs_initclip(pgs)) < 0 ||
- (code = gs_setlinewidth(pgs, 1.0)) < 0 ||
- (code = gs_setlinecap(pgs, gs_cap_butt)) < 0 ||
- (code = gs_setlinejoin(pgs, gs_join_miter)) < 0 ||
- (code = gs_setdash(pgs, (float *)0, 0, 0.0)) < 0 ||
- (code = gs_setgray(pgs, 0.0)) < 0 ||
- (code = gs_setmiterlimit(pgs, 10.0)) < 0
- ) return code;
- return 0;
- }
-
- /* setflat */
- int
- gs_setflat(gs_state *pgs, floatp flat)
- { if ( flat <= 0.2 ) flat = 0.2;
- else if ( flat > 100 ) flat = 100;
- pgs->flatness = flat;
- return 0;
- }
-
- /* currentflat */
- float
- gs_currentflat(const gs_state *pgs)
- { return pgs->flatness;
- }
-
- /* setstrokeadjust */
- int
- gs_setstrokeadjust(gs_state *pgs, int stroke_adjust)
- { pgs->stroke_adjust = stroke_adjust;
- return 0;
- }
-
- /* currentstrokeadjust */
- int
- gs_currentstrokeadjust(const gs_state *pgs)
- { return pgs->stroke_adjust;
- }
-
- /* ------ Internal routines ------ */
-
- /* Allocate a graphics state object and its contents, */
- /* optionally initializing it from an existing object. */
- /* Return 0 if the allocation fails. */
- private gs_state *
- alloc_gstate(gs_memory_t *mem, const gs_state *pold, client_name_t cname)
- { gs_state *pgs = gs_alloc_struct(mem, gs_state, &st_gstate, cname);
- if ( pgs == 0 ) return 0;
- if ( pold != 0 )
- *pgs = *pold;
- else
- pgs->cie_render = 0,
- pgs->black_generation = 0,
- pgs->undercolor_removal = 0,
- pgs->transfer.red = pgs->transfer.green =
- pgs->transfer.blue = pgs->transfer.gray = 0,
- pgs->cie_joint_caches = 0,
- pgs->client_data = 0;
- pgs->memory = mem;
- if ( alloc_gstate_contents(pgs) < 0 )
- { gs_free_object(mem, pgs, cname);
- return 0;
- }
- return pgs;
- }
-
- /* Allocate the contents of a graphics state object. */
- /* Return -1 if the allocation fails. */
- /* Note that the contents have been smashed in this case. */
- private int
- alloc_gstate_contents(register gs_state *pgs)
- { gs_memory_t *mem = pgs->memory;
- static const char cname[] = "alloc_gstate_contents";
- gs_state_contents *cont =
- gs_alloc_struct(mem, gs_state_contents, &st_gstate_contents, cname);
- if ( cont == 0 ) return -1;
- pgs->contents = cont;
- #define gset(element)\
- pgs->element = &cont->element;
- gset(path);
- gset(clip_path);
- gset(line_params);
- gset(halftone);
- gset(dev_ht);
- gset(color_space);
- cont->color_space.type = &gs_color_space_type_DeviceGray; /* for cs_adjust_counts */
- gset(ccolor);
- gset(dev_color);
- #undef gset
- /* Only allocate one transfer map if none exist. */
- if ( pgs->transfer.gray == 0 )
- { rc_alloc_struct_0(pgs->transfer.gray, gx_transfer_map,
- &st_transfer_map, mem, goto uty, cname);
- pgs->transfer.gray->proc = null_transfer;
- pgs->transfer.gray->values[0] = frac_0;
- }
- rc_increment(pgs->transfer.gray);
- #define gtalloc(element)\
- if ( pgs->element == 0 )\
- pgs->element = pgs->transfer.gray;\
- rc_increment(pgs->element)
- gtalloc(transfer.red);
- gtalloc(transfer.green);
- gtalloc(transfer.blue);
- #undef gtalloc
- if ( pgs->client_data != 0 )
- { if ( (pgs->client_data =
- (*pgs->client_procs.alloc)(mem)) == 0
- )
- goto ud;
- }
- rc_increment(pgs->cie_render);
- rc_increment(pgs->black_generation);
- rc_increment(pgs->undercolor_removal);
- rc_increment(pgs->cie_joint_caches);
- return 0;
- /* Undo partial allocations if an allocation failed. */
- #define gunalloc(element)\
- rc_decrement(pgs->element, mem, cname)
- ud: gunalloc(transfer.gray);
- gunalloc(transfer.blue);
- gunalloc(transfer.green);
- gunalloc(transfer.red);
- uty: gs_free_object(mem, cont, cname);
- return -1;
- #undef gunalloc
- }
-
- /* Free the contents of a graphics state, but not the state itself. */
- private void
- free_gstate_contents(gs_state *pgs)
- { gs_memory_t *mem = pgs->memory;
- static const char cname[] = "free_gstate_contents";
- #define gfree(element, pstype)\
- gs_free_object(mem, pgs->element, cname)
- gx_path_release(pgs->path);
- gx_cpath_release(pgs->clip_path);
- rc_decrement(pgs->cie_joint_caches, mem, cname);
- rc_decrement(pgs->transfer.gray, mem, cname);
- rc_decrement(pgs->transfer.blue, mem, cname);
- rc_decrement(pgs->transfer.green, mem, cname);
- rc_decrement(pgs->transfer.red, mem, cname);
- rc_decrement(pgs->undercolor_removal, mem, cname);
- rc_decrement(pgs->black_generation, mem, cname);
- rc_decrement(pgs->cie_render, mem, cname);
- cs_adjust_counts(pgs, -1);
- if ( pgs->client_data != 0 )
- (*pgs->client_procs.free)(pgs->client_data, mem);
- gs_free_object(mem, pgs->contents, cname);
- #undef gfree
- }
-
- /* Copy the composite parts of a graphics state. */
- private void
- copy_gstate_contents(gs_state *pto, const gs_state *pfrom)
- { gs_memory_t *mem = pto->memory;
- static const char cname[] = "copy_gstate_contents";
- /* It's OK to decrement the counts before incrementing them, */
- /* because anything that is going to survive has a count of */
- /* at least 2 (pto and somewhere else) initially. */
- cs_adjust_counts(pto, -1);
- *pto->contents = *pfrom->contents;
- cs_adjust_counts(pto, 1);
- #define rccopy(element)\
- rc_assign(pto->element, pfrom->element, mem, cname);
- if ( pfrom->pattern_cache != 0 )
- pto->pattern_cache = pfrom->pattern_cache;
- rccopy(cie_joint_caches);
- rccopy(transfer.gray);
- rccopy(transfer.blue);
- rccopy(transfer.green);
- rccopy(transfer.red);
- rccopy(undercolor_removal);
- rccopy(black_generation);
- rccopy(cie_render);
- #undef rccopy
- if ( pfrom->client_data != 0 )
- (*pfrom->client_procs.copy)(pto->client_data, pfrom->client_data);
- gx_path_share(pto->path);
- gx_cpath_share(pto->clip_path);
- }
-