Beispiel #1
0
static void eprn_flag_mismatch(const struct s_eprn_Device *eprn,
  bool no_match)
{
  if (eprn->fmr != NULL) (*eprn->fmr)(eprn, no_match);
  else {
    const char *epref = eprn->CUPS_messages? CUPS_ERRPREF: "";

    eprintf2("%s" ERRPREF "The %s does not support ",
      epref, eprn->cap->name);
    if (eprn->desired_flags == 0) eprintf("an empty set of media flags");
    else {
      eprintf("the \"");
      print_flags(eprn->desired_flags, eprn->flag_desc);
      eprintf("\" flag(s)");
    }
    eprintf1("\n%s  (ignoring presence or absence of \"", epref);
    {
      ms_MediaCode optional = MS_TRANSVERSE_FLAG;
      if (eprn->optional_flags != NULL) {
        const ms_MediaCode *of = eprn->optional_flags;
        while (*of != ms_none) optional |= *of++;
      }
      print_flags(optional, eprn->flag_desc);
    }
    eprintf("\") for ");
    if (no_match) eprintf("any"); else eprintf("this");
    eprintf(" page size.\n");
  }

  return;
}
Beispiel #2
0
int eprn_output_page(gx_device *dev, int num_copies, int flush)
{
  eprn_Eprn *eprn = &((eprn_Device *)dev)->eprn;
  int rc;

#ifdef EPRN_TRACE
  clock_t start_time = clock();
  if_debug0(EPRN_TRACE_CHAR, "! eprn_output_page()...\n");
#endif

  /* Initialize eprn_get_planes() data */
  eprn->next_y = 0;
  if (eprn->intensity_rendering == eprn_IR_FloydSteinberg) {
    /* Fetch the first line and store it in 'next_scan_line'. */
    if (eprn_fetch_scan_line((eprn_Device *)dev, &eprn->next_scan_line) == 0)
      eprn->next_y++;
  }

  /* Ship out */
  rc = gdev_prn_output_page(dev, num_copies, flush);

  /*  CUPS page accounting message. The CUPS documentation is not perfectly
      clear on whether one should generate this message before printing a page
      or after printing has been successful. The rasterto* filters generate it
      before sending the page, but as the scheduler uses these messages for
      accounting, this seems unfair.
  */
  if (rc == 0 && eprn->CUPS_accounting)
    eprintf2("PAGE: %ld %d\n", dev->ShowpageCount, num_copies);
    /* The arguments are the number of the page, starting at 1, and the number
       of copies of that page. */

#ifndef EPRN_NO_PAGECOUNTFILE
  /* On success, record the number of pages printed */
  if (rc == 0 && eprn->pagecount_file != NULL) {
    assert(num_copies > 0);     /* because of signed/unsigned */
    if (pcf_inccount(eprn->pagecount_file, num_copies) != 0) {
      /* pcf_inccount() has issued an error message. */
      eprintf(
        "  No further attempts will be made to access the page count file.\n");
      gs_free(dev->memory->non_gc_memory, eprn->pagecount_file, strlen(eprn->pagecount_file) + 1,
        sizeof(char), "eprn_output_page");
      eprn->pagecount_file = NULL;
    }
  }
#endif  /* !EPRN_NO_PAGECOUNTFILE */

  /* If soft tumble has been demanded, ensure the get_initial_matrix procedure
     is consulted for the next page */
  if (eprn->soft_tumble) eprn_forget_defaultmatrix(dev->memory->non_gc_memory);

#ifdef EPRN_TRACE
  if_debug1(EPRN_TRACE_CHAR, "! eprn_output_page() terminates after %f s.\n",
    ((float)(clock() - start_time))/CLOCKS_PER_SEC);
#endif

  return rc;
}
Beispiel #3
0
/*
 * Handle the end of a character.  Return 0 if this is really the end of a
 * character, or 1 if we still have to process the accent of a seac.
 * In the latter case, the interpreter control stack has been set up to
 * point to the start of the accent's CharString; the caller must
 * also set ptx/y to pcis->position.x/y.
 */
int
gs_type1_endchar(gs_type1_state * pcis)
{
    gs_imager_state *pis = pcis->pis;

    if (pcis->seac_accent >= 0) {	/* We just finished the base character of a seac. */
	/* Do the accent. */
	gs_font_type1 *pfont = pcis->pfont;
	gs_glyph_data_t agdata;
	int achar = pcis->seac_accent;
	gs_const_string gstr;
	int code;

	agdata.memory = pfont->memory;
	pcis->seac_accent = -1;
	/* Reset the coordinate system origin */
	pcis->asb_diff = pcis->asb - pcis->compound_lsb.x;
	pcis->adxy = pcis->save_adxy;
	pcis->os_count = 0;	/* clear */
	/* Clear the ipstack, in case the base character */
	/* ended inside a subroutine. */
	pcis->ips_count = 1;
	/* Ask the caller to provide the accent's CharString. */
	code = pfont->data.procs.seac_data(pfont, achar, NULL, &gstr, &agdata);
	if (code == gs_error_undefined) {
	    /* 
	     * The font is missing the accent's CharString (due to
	     * bad subsetting).  Just end drawing here without error. 
	     * This is like Acrobat Reader behaves.
	     */
	    char buf0[gs_font_name_max + 1], buf1[30];
	    int l0 = min(pcis->pfont->font_name.size, sizeof(buf0) - 1);
	    int l1 = min(gstr.size, sizeof(buf1) - 1);

	    memcpy(buf0, pcis->pfont->font_name.chars, l0);
	    buf0[l0] = 0;
	    memcpy(buf1, gstr.data, l1);
	    buf1[l1] = 0;
	    eprintf2("The font '%s' misses the glyph '%s' . Continue skipping the glyph.", buf0, buf1);
	    return 0;
	}
	if (code < 0)
	    return code;
	/* Continue with the supplied string. */
	pcis->ips_count = 1;
	pcis->ipstack[0].cs_data = agdata;
	return 1;
    }
    if (pcis->pfont->PaintType == 0)
	pis->fill_adjust.x = pis->fill_adjust.y = -1;
    /* Set the flatness for curve rendering. */
    if (!pcis->no_grid_fitting)
	gs_imager_setflat(pis, pcis->flatness);
    return 0;
}
Beispiel #4
0
int eprn_set_page_layout(eprn_Device *dev)
{
  bool
    no_match = true,
     /* Are the requested flags supported for some size? */
    landscape = dev->MediaSize[0] > dev->MediaSize[1];
     /* It's not documented, but 'MediaSize' is the requested "PageSize" page
        device parameter value and hence is to be interpreted in default (not
        default default!) user space. */
  const char *epref = dev->eprn.CUPS_messages? CUPS_ERRPREF: "";
  const eprn_CustomPageDescription
    *best_cmatch = NULL;        /* best custom page size match */
  eprn_Eprn
    *eprn = &dev->eprn;
  const eprn_PageDescription
    *best_cdmatch = NULL,     /* best custom page size match in discrete list*/
    *best_dmatch = NULL,        /* best discrete match */
    *pd;                        /* loop variable */
  float
    /* Page width and height in bp with w <= h (in a moment): */
    w = dev->MediaSize[0],
    h = dev->MediaSize[1],
    /* pixmap device space margins in bp (canonical order): */
    margins[4];
  int
    quarters;
  ms_MediaCode
    desired = eprn->desired_flags;

#ifdef EPRN_TRACE
  if_debug3(EPRN_TRACE_CHAR,
    "! eprn_set_page_layout(): PageSize = [%.0f %.0f], "
      "desired_flags = 0x%04X.\n",
    dev->MediaSize[0], dev->MediaSize[1], (unsigned int)desired);
#endif

  /* Ensure w <= h */
  if (w > h) {
    float temp;
    temp = w; w = h; h = temp;
    /* This has effectively split 'MediaSize[]' into 'w', 'h' and 'landscape'.
     */
  }

  /* Initialization of primary return value */
  eprn->code = ms_none;

  /* Put the LeadingEdge value into the desired flag pattern if it's set */
  if (eprn->leading_edge_set) {
    if (eprn->default_orientation % 2 == 0)     /* true on short edge first */
      desired &= ~MS_TRANSVERSE_FLAG;
    else
      desired |= MS_TRANSVERSE_FLAG;
  }

  /* Find best match in discrete sizes */
  if (eprn->media_overrides == NULL) pd = eprn->cap->sizes;
  else pd = eprn->media_overrides;
  while (pd->code != ms_none) {
    const ms_SizeDescription *ms = ms_find_size_from_code(pd->code);
    if (ms->dimen[0] > 0.0 /* ignore variable sizes */ &&
        fabs(w - ms->dimen[0])  <= 5.0 &&
        fabs(h - ms->dimen[1]) <= 5.0) {
       /* The size does match at 5 bp tolerance. This value has been chosen
          arbitrarily to be equal to PostScript's PageSize matching tolerance
          during media selection. The tolerance should really be that at which
          the printer in question distinguishes between sizes or smaller than
          that in order to at least prevent printing on unsupported sizes.
        */
      if (best_dmatch == NULL ||
          better_flag_match(desired, eprn->optional_flags, best_dmatch->code,
            pd->code))
        best_dmatch = pd;
      if (flag_match(desired, eprn->optional_flags, pd->code))
        no_match = false;
    }
    pd++;
  }

  /* Next find the best match among the custom size descriptions */
  if (eprn->cap->custom != NULL) {
    const eprn_CustomPageDescription *cp = eprn->cap->custom;

    /* First check whether the size is in the supported range */
    while (cp->width_max > 0.0) {
      if (cp->width_min  <= w && w <= cp->width_max &&
          cp->height_min <= h && h <= cp->height_max) {
        /* The size does match. */
        if (best_cmatch == NULL ||
            better_flag_match(desired, eprn->optional_flags, best_cmatch->code,
              cp->code))
          best_cmatch = cp;
        if (eprn->media_overrides == NULL &&
            flag_match(desired, eprn->optional_flags, cp->code))
          no_match = false;
      }
      cp++;
    }

    /* If we have read a media configuration file, the flags to be matched
       must be sought in 'media_overrides'. */
    if (best_cmatch != NULL && eprn->media_overrides != NULL) {
      for (pd = eprn->media_overrides; pd->code != ms_none; pd++) {
        if (ms_without_flags(pd->code) == ms_CustomPageSize) {
          if (best_cdmatch == NULL ||
              better_flag_match(desired, eprn->optional_flags,
                best_cdmatch->code, pd->code))
            best_cdmatch = pd;
          if (flag_match(desired, eprn->optional_flags, pd->code))
            no_match = false;
        }
      }
    }
  }

  /*  Now the 'best_*match' variables indicate for each of the categories of
      page descriptions to which extent the size is supported at all (non-NULL
      value) and what the best flag match in the category is. Here we now check
      for NULL values, i.e., size matches. */
  if (best_dmatch == NULL) {
    /* No discrete match */
    if (best_cmatch == NULL) {
      /* No match at all. */
      eprintf3("%s" ERRPREF
        "This document requests a page size of %.0f x %.0f bp.\n",
           epref, dev->MediaSize[0], dev->MediaSize[1]);
      if (eprn->cap->custom == NULL) {
        /* The printer does not support custom page sizes */
        if (eprn->media_overrides != NULL)
          eprintf1(
            "%s  The media configuration file does not contain an entry for "
              " this size.\n", epref);
        else
          eprintf2("%s  This size is not supported by the %s.\n",
            epref, eprn->cap->name);
      }
      else
        eprintf3(
          "%s  This size is not supported as a discrete size and it exceeds "
            "the\n"
          "%s  custom page size limits for the %s.\n",
          epref, epref, eprn->cap->name);
      return -1;
    }
    if (eprn->media_overrides != NULL && best_cdmatch == NULL) {
      eprintf6("%s" ERRPREF
        "This document requests a page size of %.0f x %.0f bp\n"
        "%s  but there is no entry for this size in the "
          "media configuration file\n"
        "%s  %s.\n",
        epref, dev->MediaSize[0], dev->MediaSize[1], epref, epref,
        eprn->media_file);
      return -1;
    }
  }
  /* Now we have: best_dmatch != NULL || best_cmatch != NULL &&
     (eprn->media_overrides == NULL || best_cdmatch != NULL). */

  /* Find a flag match among the size matches found so far */
  {
    ms_MediaCode custom_code = ms_none;
      /* best custom page size match (either from cmatch or dcmatch) */
    if (best_cmatch != NULL &&
        (eprn->media_overrides == NULL || best_cdmatch != NULL))
      custom_code = (eprn->media_overrides == NULL?
        best_cmatch->code: best_cdmatch->code);

    if (best_dmatch == NULL ||
        best_cmatch != NULL &&
          better_flag_match(desired, eprn->optional_flags, best_dmatch->code,
            custom_code)) {
      if (flag_match(desired, eprn->optional_flags, custom_code)) {
        if (eprn->media_overrides == NULL) {
          eprn->code = best_cmatch->code;
          margins[0] = best_cmatch->left;
          margins[1] = best_cmatch->bottom;
          margins[2] = best_cmatch->right;
          margins[3] = best_cmatch->top;
        }
        else {
          eprn->code = best_cdmatch->code;
          margins[0] = best_cdmatch->left;
          margins[1] = best_cdmatch->bottom;
          margins[2] = best_cdmatch->right;
          margins[3] = best_cdmatch->top;
        }
      }
    }
    else {
      if (flag_match(desired, eprn->optional_flags, best_dmatch->code)) {
        eprn->code = best_dmatch->code;
        margins[0] = best_dmatch->left;
        margins[1] = best_dmatch->bottom;
        margins[2] = best_dmatch->right;
        margins[3] = best_dmatch->top;
      }
    }
  }
  /* If we've found a match, 'code' is no longer 'ms_none'. */
  if (eprn->code == ms_none) {
    eprn_flag_mismatch(eprn, no_match);
    return -1;
  }

  /* Adapt the orientation of default default user space if not prescribed */
  if (!eprn->leading_edge_set) {
    if (eprn->code & MS_TRANSVERSE_FLAG) eprn->default_orientation = 3;
     /* This leads to 0 if landscape orientation is requested. */
    else eprn->default_orientation = 0;
  }

  /*
    Now 'eprn->default_orientation % 2' describes the sheet's orientation in
    pixmap device space. If this does not agree with the width and height
    values in the device instance, we'll have to adapt them.
    This is only necessary if there is a significant difference between width
    and height.
   */
  if (fabs(w - h) > 1 /* arbitrary */ &&
    (eprn->default_orientation % 2 == 0) !=
        (dev->width/dev->HWResolution[0] <= dev->height/dev->HWResolution[1])) {
    bool reallocate = false;

#ifdef EPRN_TRACE
    if_debug0(EPRN_TRACE_CHAR,
      "! eprn_set_page_layout(): width-height change is necessary.\n");
#endif

    /* Free old storage if the device is open */
    if (dev->is_open) {
#ifdef EPRN_TRACE
      if_debug0(EPRN_TRACE_CHAR, "! eprn_set_page_layout(): Device is open.\n");
#endif
      reallocate = true;
       /* One could try and call the allocation/reallocation routines of the
          prn device directly, but they are not available in older ghostscript
          versions and this method is safer anyway because it relies on a
          documented API. */
      gdev_prn_close((gx_device *)dev);         /* ignore the result */
    }

    /*  Now set width and height via gx_device_set_media_size(). This function
        sets 'MediaSize[]', 'width', and 'height' based on the assumption that
        default user space has a y axis which is vertical in pixmap device
        space. This may be wrong and we have to fix it. Because fixing
        'MediaSize[]' is simpler, gx_device_set_media_size() is called such
        that it gives the correct values for 'width' and 'height'. */
    if (eprn->default_orientation % 2 == 0) {
      /* portrait orientation of the sheet in pixmap device space */
      gx_device_set_media_size((gx_device *)dev, w, h);
      if (landscape) {
        dev->MediaSize[0] = h;
        dev->MediaSize[1] = w;
      }
    }
    else {
      /* landscape orientation in pixmap device space (transverse) */
      gx_device_set_media_size((gx_device *)dev, h, w);
      if (!landscape) {
        dev->MediaSize[0] = w;
        dev->MediaSize[1] = h;
      }
    }

    /* If the device is/was open, reallocate storage */
    if (reallocate) {
      int rc;

      rc = gdev_prn_open((gx_device *)dev);
      if (rc < 0) {
        eprintf2("%s" ERRPREF
          "Failure of gdev_prn_open(), code is %d.\n",
          epref, rc);
        return rc;
      }
    }
  }

  /* Increase the bottom margin for coloured modes except if it is exactly
     zero */
  if (eprn->colour_model != eprn_DeviceGray && margins[1] != 0.0)
    margins[1] += eprn->cap->bottom_increment;

  /* Number of +90-degree rotations needed for default user space: */
  quarters = eprn->default_orientation;
  if (landscape) quarters = (quarters + 1)%4;

  /* Store the top and left margins in the device structure for use by
     eprn_get_initial_matrix() and set the margins of the printable area if
     we may.
     gx_device_set_margins() (see gsdevice.c) copies the margins[] array to
     HWMargins[] which is presumably to be interpreted in default user space
     (see gs_initclip() in gspath.c), and if its second argument is true it
     also modifies the offset variable Margins[]. The first property means
     that gx_device_set_margins() can only be used if default user space and
     pixmap device space have the same "up" direction, and the second
     appropriates a parameter which is intended for the user.
  */
  if (eprn->keep_margins) {
    eprn->down_shift  = dev->HWMargins[3 - quarters];
    eprn->right_shift = dev->HWMargins[(4 - quarters)%4];
  }
  else {
    int j;

    eprn->down_shift  = margins[3];
    eprn->right_shift = margins[0];

    if (quarters != 0) {
       /* The "canonical margin order" for ghostscript is left, bottom, right,
          top. Hence for, e.g., a +90-degree rotation ('quarters' is 1) of
          default user space with respect to pixmap device space the left
          margin (index 0) in default user space is actually the bottom margin
          (index 1) in pixmap device space, the bottom margin is the right one,
          etc.
        */
      for (j = 0; j < 4; j++) dev->HWMargins[j] = margins[(j+quarters)%4];
      /* 'HWMargins[]' is in bp (see gxdevcli.h) */
    }
    else {
      /* Convert to inches */
      for (j = 0; j < 4; j++) margins[j] /= BP_PER_IN;

      gx_device_set_margins((gx_device *)dev, margins, false);
       /* Of course, I could set HWMargins[] directly also in this case. This
          way is however less prone to break on possible future incompatible
          changes to ghostscript and it covers the most frequent case (portrait
          and short edge first). */
    }
  }

  return 0;
}