/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * Roland Mainz * Ken Herron * * This Original Code has been modified by IBM Corporation. Modifications made by IBM * described herein are Copyright (c) International Business Machines Corporation, 2000. * Modifications to Mozilla code or documentation identified per MPL Section 3.3 * * Date Modified by Description of modification * 04/20/2000 IBM Corp. OS/2 VisualAge build. * 10/09/2000 IPLabs Linux Team True Unicode glyps support added. */ #include "gfx-config.h" #define FORCE_PR_LOG /* Allow logging in the release build */ #define PR_LOGGING 1 #include "prlog.h" #include "nscore.h" #include "nsIAtom.h" #include "nsPostScriptObj.h" #include "isotab.c" #include "nsFont.h" #include "nsIImage.h" #include "nsAFMObject.h" #include "nsIServiceManager.h" #include "nsICharsetConverterManager.h" #include "nsIUnicodeEncoder.h" #include "nsIUnicodeDecoder.h" #include "nsReadableUtils.h" #include "nsICharsetAlias.h" #include "nsNetUtil.h" #include "nsIPersistentProperties2.h" #include "nsCRT.h" #include "nsFontMetricsPS.h" #include "nsPaperPS.h" #ifndef NS_BUILD_ID #include "nsBuildID.h" #endif /* !NS_BUILD_ID */ #include "prenv.h" #include "prprf.h" #include "prerror.h" #include #include #ifdef MOZ_ENABLE_FREETYPE2 #include "nsType8.h" #endif #ifdef PR_LOGGING static PRLogModuleInfo *nsPostScriptObjLM = PR_NewLogModule("nsPostScriptObj"); #endif /* PR_LOGGING */ /* A private class to format floating-point values into strings. This * is used to write floating-point values into the postscript document. * printf()-based functions can't be used because they may generate * locale-ized output, e.g. using a comma for the decimal point, which * isn't a valid postscript number. */ class fpCString : public nsCAutoString { public: inline fpCString(float aValue) { AppendFloat(aValue); } }; #define NS_PS_RED(x) (((float)(NS_GET_R(x))) / 255.0) #define NS_PS_GREEN(x) (((float)(NS_GET_G(x))) / 255.0) #define NS_PS_BLUE(x) (((float)(NS_GET_B(x))) / 255.0) #define NS_PS_GRAY(x) (((float)(x)) / 255.0) #define NS_RGB_TO_GRAY(r,g,b) ((int(r) * 77 + int(g) * 150 + int(b) * 29) / 256) #define NS_IS_BOLD(x) (((x) >= 401) ? 1 : 0) static NS_DEFINE_CID(kPrefCID, NS_PREF_CID); static NS_DEFINE_CID(kCharsetConverterManagerCID, NS_ICHARSETCONVERTERMANAGER_CID); /* * global */ static nsIUnicodeEncoder *gEncoder = nsnull; static nsHashtable *gU2Ntable = nsnull; static nsIPref *gPrefs = nsnull; static nsHashtable *gLangGroups = nsnull; static PRBool FreeU2Ntable(nsHashKey * aKey, void *aData, void *aClosure) { delete(int *) aData; return PR_TRUE; } static PRBool ResetU2Ntable(nsHashKey * aKey, void *aData, void *aClosure) { PS_LangGroupInfo *linfo = (PS_LangGroupInfo *)aData; if (linfo && linfo->mU2Ntable) { linfo->mU2Ntable->Reset(FreeU2Ntable, nsnull); } return PR_TRUE; } static PRBool FreeLangGroups(nsHashKey * aKey, void *aData, void *aClosure) { PS_LangGroupInfo *linfo = (PS_LangGroupInfo *) aData; NS_IF_RELEASE(linfo->mEncoder); if (linfo->mU2Ntable) { linfo->mU2Ntable->Reset(FreeU2Ntable, nsnull); delete linfo->mU2Ntable; linfo->mU2Ntable = nsnull; } delete linfo; linfo = nsnull; return PR_TRUE; } static void PrintAsDSCTextline(FILE *f, const char *text, int maxlen) { NS_ASSERTION(maxlen > 1, "bad max length"); if (*text != '(') { // Format as DSC textline type fprintf(f, "%.*s", maxlen, text); return; } // Fallback: Format as DSC text type fprintf(f, "("); int len = maxlen - 2; while (*text && len > 0) { if (!isprint(*text)) { if (len < 4) break; fprintf(f, "\\%03o", *text); len -= 4; } else if (*text == '(' || *text == ')' || *text == '\\') { if (len < 2) break; fprintf(f, "\\%c", *text); len -= 2; } else { fprintf(f, "%c", *text); len--; } text++; } fprintf(f, ")"); } /** --------------------------------------------------- * Default Constructor * @update 2/1/99 dwc */ nsPostScriptObj::nsPostScriptObj() : mPrintSetup(nsnull), mPrintContext(nsnull), mTitle(nsnull) { PR_LOG(nsPostScriptObjLM, PR_LOG_DEBUG, ("nsPostScriptObj::nsPostScriptObj()\n")); nsServiceManager::GetService(kPrefCID, NS_GET_IID(nsIPref), (nsISupports**) &gPrefs); gLangGroups = new nsHashtable(); } /** --------------------------------------------------- * Destructor * @update 2/1/99 dwc */ nsPostScriptObj::~nsPostScriptObj() { PR_LOG(nsPostScriptObjLM, PR_LOG_DEBUG, ("nsPostScriptObj::~nsPostScriptObj()\n")); // The mPrintContext can be null // if opening the PostScript document // fails. Giving an invalid path, relative path // or a directory which the user does not have // write permissions for will fail to open a document // see bug 85535 if (mPrintContext) { if (mPrintSetup->out) { fclose(mPrintSetup->out); mPrintSetup->out = nsnull; } if (mPrintSetup->tmpBody) { fclose(mPrintSetup->tmpBody); mPrintSetup->tmpBody = nsnull; } finalize_translation(); } // Cleanup things allocated along the way if (nsnull != mTitle){ nsMemory::Free(mTitle); } if (nsnull != mPrintContext){ if (nsnull != mPrintContext->prInfo){ delete mPrintContext->prInfo; } if (nsnull != mPrintContext->prSetup){ delete mPrintContext->prSetup; } delete mPrintContext; mPrintContext = nsnull; } if (nsnull != mPrintSetup) { delete mPrintSetup; mPrintSetup = nsnull; } NS_IF_RELEASE(gPrefs); if (gLangGroups) { gLangGroups->Reset(FreeLangGroups, nsnull); delete gLangGroups; gLangGroups = nsnull; } if (mDocProlog) mDocProlog->Remove(PR_FALSE); if (mDocScript) mDocScript->Remove(PR_FALSE); PR_LOG(nsPostScriptObjLM, PR_LOG_DEBUG, ("nsPostScriptObj::~nsPostScriptObj(): printing done.")); } void nsPostScriptObj::settitle(PRUnichar * aTitle) { if (aTitle) { mTitle = ToNewCString(nsDependentString(aTitle)); } } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/20/2004 kherron */ nsresult nsPostScriptObj::Init( nsIDeviceContextSpecPS *aSpec ) { PRBool isGray, isAPrinter, isFirstPageFirst; int landscape; const char *printername; nsresult rv; PrintInfo* pi = new PrintInfo(); mPrintSetup = new PrintSetup(); if( (nsnull!=pi) && (nsnull!=mPrintSetup) ){ memset(mPrintSetup, 0, sizeof(struct PrintSetup_)); mPrintSetup->color = PR_TRUE; // Image output mPrintSetup->deep_color = PR_TRUE; // 24 bit color output mPrintSetup->reverse = 0; // Output order, 0 is acsending if ( aSpec != nsnull ) { aSpec->GetCopies(mPrintSetup->num_copies); aSpec->GetGrayscale( isGray ); if ( isGray == PR_TRUE ) { mPrintSetup->color = PR_FALSE; mPrintSetup->deep_color = PR_FALSE; } aSpec->GetFirstPageFirst( isFirstPageFirst ); if ( isFirstPageFirst == PR_FALSE ) mPrintSetup->reverse = 1; // Clean up tempfile remnants of any previous print job if (mDocProlog) mDocProlog->Remove(PR_FALSE); if (mDocScript) mDocScript->Remove(PR_FALSE); aSpec->GetToPrinter( isAPrinter ); if (isAPrinter) { /* Define the destination printer (queue). * We assume that the print command is set to * "lpr ${MOZ_PRINTER_NAME:+'-P'}${MOZ_PRINTER_NAME}" * - which means that if the ${MOZ_PRINTER_NAME} env var is not empty * the "-P" option of lpr will be set to the printer name. */ /* get printer name */ aSpec->GetPrinterName(&printername); /* do not set the ${MOZ_PRINTER_NAME} env var if we want the default * printer */ if (printername) { /* strip the leading NS_POSTSCRIPT_DRIVER_NAME string */ printername = printername + NS_POSTSCRIPT_DRIVER_NAME_LEN; if (!strcmp(printername, "default")) printername = ""; } else printername = ""; /* Construct an environment string MOZ_PRINTER_NAME= * and add it to the environment. * On a POSIX system the original buffer becomes part of the * environment, so it must remain valid until replaced. To preserve * the ability to unload shared libraries, we have to either remove * the string from the environment at unload time or else store the * string in the heap, where it'll be left behind after unloading * the library. */ static char *moz_printer_string; char *old_printer_string = moz_printer_string; moz_printer_string = PR_smprintf("MOZ_PRINTER_NAME=%s", printername); #ifdef DEBUG printf("setting '%s'\n", moz_printer_string); #endif if (!moz_printer_string) { /* We're probably out of memory */ moz_printer_string = old_printer_string; return (PR_OUT_OF_MEMORY_ERROR == PR_GetError()) ? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_UNEXPECTED; } else { PR_SetEnv(moz_printer_string); if (old_printer_string) PR_smprintf_free(old_printer_string); } aSpec->GetCommand(&mPrintSetup->print_cmd); // Create a temporary file for the document prolog rv = mTempfileFactory.CreateTempFile(getter_AddRefs(mDocProlog), &mPrintSetup->out, "w+"); NS_ENSURE_SUCCESS(rv, NS_ERROR_GFX_PRINTER_FILE_IO_ERROR); NS_POSTCONDITION(nsnull != mPrintSetup->out, "CreateTempFile succeeded but no file handle"); } else { const char *path; aSpec->GetPath(&path); rv = NS_NewNativeLocalFile(nsDependentCString(path), PR_FALSE, getter_AddRefs(mDocProlog)); rv = mDocProlog->OpenANSIFileDesc("w", &mPrintSetup->out); if (NS_FAILED(rv)) return NS_ERROR_GFX_PRINTER_COULD_NOT_OPEN_FILE; NS_POSTCONDITION(nsnull != mPrintSetup->out, "OpenANSIFileDesc succeeded but no file handle"); mPrintSetup->print_cmd = NULL; // Indicate print-to-file } // Open the temporary file for the document script (printable content) rv = mTempfileFactory.CreateTempFile(getter_AddRefs(mDocScript), &mPrintSetup->tmpBody, "w+"); if (NS_FAILED(rv)) { fclose(mPrintSetup->out); mPrintSetup->out = nsnull; mDocProlog->Remove(PR_FALSE); mDocProlog = nsnull; return NS_ERROR_GFX_PRINTER_FILE_IO_ERROR; } NS_POSTCONDITION(nsnull != mPrintSetup->tmpBody, "CreateTempFile succeeded but no file handle"); } else return NS_ERROR_FAILURE; /* make sure the open worked */ if (!mPrintSetup->out) return NS_ERROR_GFX_PRINTER_CMD_FAILURE; mPrintContext = new PSContext(); memset(mPrintContext, 0, sizeof(struct PSContext_)); memset(pi, 0, sizeof(struct PrintInfo_)); /* Find PS paper size record by name */ aSpec->GetPaperName(&(mPrintSetup->paper_name)); nsPaperSizePS paper; if (!paper.Find(mPrintSetup->paper_name)) return NS_ERROR_GFX_PRINTER_PAPER_SIZE_NOT_SUPPORTED; aSpec->GetLandscape( landscape ); mPrintSetup->width = NS_MILLIMETERS_TO_TWIPS(paper.Width_mm()); mPrintSetup->height = NS_MILLIMETERS_TO_TWIPS(paper.Height_mm()); if (landscape) { nscoord temp = mPrintSetup->width; mPrintSetup->width = mPrintSetup->height; mPrintSetup->height = temp; } #ifdef DEBUG printf("\nPaper Width = %d twips (%gmm) Height = %d twips (%gmm)\n", mPrintSetup->width, paper.Width_mm(), mPrintSetup->height, paper.Height_mm()); #endif mPrintSetup->header = "header"; mPrintSetup->footer = "footer"; mPrintSetup->sizes = nsnull; mPrintSetup->landscape = (landscape) ? PR_TRUE : PR_FALSE; // Rotated output //mPrintSetup->landscape = PR_FALSE; mPrintSetup->underline = PR_TRUE; // underline links mPrintSetup->scale_images = PR_TRUE; // Scale unsized images which are too big mPrintSetup->scale_pre = PR_FALSE; // do the pre-scaling thing mPrintSetup->rules = 1.0f; // Scale factor for rulers mPrintSetup->n_up = 0; // cool page combining mPrintSetup->bigger = 1; // Used to init sizes if sizesin NULL mPrintSetup->prefix = ""; // For text xlate, prepended to each line mPrintSetup->eol = ""; // For text translation, line terminator mPrintSetup->bullet = "+"; // What char to use for bullets #ifdef NOTYET URL_Struct_* url = new URL_Struct_; memset(url, 0, sizeof(URL_Struct_)); mPrintSetup->url = url; // url of doc being translated #else mPrintSetup->url = nsnull; #endif mPrintSetup->completion = nsnull; // Called when translation finished mPrintSetup->carg = nsnull; // Data saved for completion routine mPrintSetup->status = 0; // Status of URL on completion mTitle = nsnull; pi->doc_title = mTitle; mPrintContext->prInfo = pi; // begin the document initialize_translation(mPrintSetup); begin_document(); mPageNumber = 1; // we are on the first page return NS_OK; } else { return NS_ERROR_FAILURE; } } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::finalize_translation() { if (mPrintContext) { free(mPrintContext->prSetup); mPrintContext->prSetup = nsnull; } } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::initialize_translation(PrintSetup* pi) { PrintSetup *dup = (PrintSetup *)malloc(sizeof(PrintSetup)); *dup = *pi; mPrintContext->prSetup = dup; } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::begin_document() { int i; FILE *f; nscoord paper_width = mPrintContext->prSetup->width; nscoord paper_height = mPrintContext->prSetup->height; const char *orientation; if (paper_height < paper_width) { // prSetup->width and height have been swapped, indicating landscape. // The bounding box etc. must be in terms of the default PS coordinate // system. nscoord temp = paper_width; paper_width = paper_height; paper_height = temp; orientation = "Landscape"; } else orientation = "Portrait"; f = mPrintContext->prSetup->out; fprintf(f, "%%!PS-Adobe-3.0\n"); fprintf(f, "%%%%BoundingBox: 0 0 %s %s\n", fpCString(NSTwipsToFloatPoints(paper_width)).get(), fpCString(NSTwipsToFloatPoints(paper_height)).get()); fprintf(f, "%%%%Creator: Mozilla PostScript module (%s/%lu)\n", "rv:" MOZILLA_VERSION, (unsigned long)NS_BUILD_ID); fprintf(f, "%%%%DocumentData: Clean8Bit\n"); fprintf(f, "%%%%DocumentPaperSizes: %s\n", mPrintSetup->paper_name); fprintf(f, "%%%%Orientation: %s\n", orientation); // hmm, n_pages is always zero so don't use it #if 0 fprintf(f, "%%%%Pages: %d\n", (int) mPrintContext->prInfo->n_pages); #else fprintf(f, "%%%%Pages: (atend)\n"); #endif if (mPrintContext->prSetup->reverse) fprintf(f, "%%%%PageOrder: Descend\n"); else fprintf(f, "%%%%PageOrder: Ascend\n"); if (nsnull != mPrintContext->prInfo->doc_title) { // DSC spec: max line length is 255 characters fprintf(f, "%%%%Title: "); PrintAsDSCTextline(f, mPrintContext->prInfo->doc_title, 230); fprintf(f, "\n"); } #ifdef NOTYET fprintf(f, "%%%%For: %n", user_name_stuff); #endif fprintf(f, "%%%%EndComments\n"); // general comments: Mozilla-specific #ifdef NOTYET fprintf(f, "\n%% MozillaURL: %s\n", mPrintContext->prSetup->url->address); #endif fprintf(f, "%% MozillaCharsetName: iso-8859-1\n\n"); // now begin prolog fprintf(f, "%%%%BeginProlog\n"); // Tell the printer what size paper it should use fprintf(f, "/setpagedevice where\n" // Test for the feature "{ pop 1 dict\n" // Set up a dictionary " dup /PageSize [ %s %s ] put\n" // Paper dimensions " setpagedevice\n" // Install settings "} if\n", fpCString(NSTwipsToFloatPoints(paper_width)).get(), fpCString(NSTwipsToFloatPoints(paper_height)).get()); fprintf(f, "["); for (i = 0; i < 256; i++){ if (*isotab[i] == '\0'){ fprintf(f, " /.notdef"); }else{ fprintf(f, " /%s", isotab[i]); } if (( i % 6) == 5){ fprintf(f, "\n"); } } fprintf(f, "] /isolatin1encoding exch def\n"); // Procedure to reencode a font fprintf(f, "%s", "/Mfr {\n" " findfont dup length dict\n" " begin\n" " {1 index /FID ne {def} {pop pop} ifelse} forall\n" " /Encoding isolatin1encoding def\n" " currentdict\n" " end\n" " definefont pop\n" "} bind def\n"); // Procedure to select and scale a font, using selectfont if available. See // Adobe Technical note 5048. Note msf args are backwards from selectfont. fprintf(f, "%s", "/Msf /selectfont where\n" " { pop { exch selectfont } }\n" " { { findfont exch scalefont setfont } }\n" " ifelse\n" " bind def\n"); for(i=0;iprSetup->out); #endif } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::begin_page() { FILE *f; f = mPrintContext->prSetup->tmpBody; fprintf(f, "%%%%Page: %d %d\n", mPageNumber, mPageNumber); fprintf(f, "%%%%BeginPageSetup\n"); if(mPrintSetup->num_copies != 1) { fprintf(f, "1 dict dup /NumCopies %d put setpagedevice\n", mPrintSetup->num_copies); } fprintf(f,"/pagelevel save def\n"); // Rescale the coordinate system from points to twips. scale(1.0 / TWIPS_PER_POINT_FLOAT, 1.0 / TWIPS_PER_POINT_FLOAT); // Rotate and shift the coordinate system for landscape if (mPrintContext->prSetup->landscape){ fprintf(f, "90 rotate 0 -%d translate\n", mPrintContext->prSetup->height); } // Try to turn on automatic stroke adjust fputs("true Msetstrokeadjust\n", f); fprintf(f, "%%%%EndPageSetup\n"); // need to reset all U2Ntable gLangGroups->Enumerate(ResetU2Ntable, nsnull); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::end_page() { fprintf(mPrintContext->prSetup->tmpBody, "pagelevel restore\n"); fprintf(mPrintContext->prSetup->tmpBody, "showpage\n"); mPageNumber++; } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ nsresult nsPostScriptObj::end_document() { nsresult rv; PR_LOG(nsPostScriptObjLM, PR_LOG_DEBUG, ("nsPostScriptObj::end_document()\n")); // insurance against breakage if (!mPrintContext || !mPrintContext->prSetup|| !mPrintContext->prSetup->out || !mPrintSetup) return NS_ERROR_GFX_PRINTER_CMD_FAILURE; FILE *f = mPrintContext->prSetup->out; // output "tmpBody" char buffer[256]; size_t length; if (!mPrintContext->prSetup->tmpBody) return NS_ERROR_GFX_PRINTER_CMD_FAILURE; /* Reset file pointer to the beginning of the temp tmpBody file... */ fseek(mPrintContext->prSetup->tmpBody, 0, SEEK_SET); /* Copy the document script (body) to the end of the prolog (header) */ while ((length = fread(buffer, 1, sizeof(buffer), mPrintContext->prSetup->tmpBody)) > 0) { fwrite(buffer, 1, length, f); } /* Close the script file handle and dispose of the temporary file */ if (mPrintSetup->tmpBody) { fclose(mPrintSetup->tmpBody); mPrintSetup->tmpBody = nsnull; } mDocScript->Remove(PR_FALSE); mDocScript = nsnull; // Finish up the document. // n_pages is zero so use mPageNumber fprintf(f, "%%%%Trailer\n"); fprintf(f, "%%%%Pages: %d\n", (int) mPageNumber - 1); fprintf(f, "%%%%EOF\n"); if (!mPrintSetup->print_cmd) { PR_LOG(nsPostScriptObjLM, PR_LOG_DEBUG, ("print to file completed.\n")); fclose(mPrintSetup->out); rv = NS_OK; } else { PR_LOG(nsPostScriptObjLM, PR_LOG_DEBUG, ("piping job to '%s'\n", mPrintSetup->print_cmd)); #ifdef VMS // VMS can't print to a pipe, so issue a print command for the // mDocProlog file. Also, we do not delete the print file here since // on OpenVMS we can not delete the file until after it has actually // printed (we use a default print command of "print /delete" to take // care of it). fclose(mPrintSetup->out); nsCAutoString prologFile; rv = mDocProlog->GetNativePath(prologFile); if (NS_SUCCEEDED(rv)) { char *prologFileExternal = GENERIC_EXTERNAL_NAME(prologFile.get(),0); char *VMSPrintCommand = PR_smprintf("%s %s", mPrintSetup->print_cmd, prologFileExternal); free(prologFileExternal); if (!VMSPrintCommand) rv = NS_ERROR_OUT_OF_MEMORY; else { PR_LOG(nsPostScriptObjLM, PR_LOG_DEBUG, ("VMS print command '%s'\n", VMSPrintCommand)); int VMSstatus = system(VMSPrintCommand); PR_smprintf_free(VMSPrintCommand); PR_LOG(nsPostScriptObjLM, PR_LOG_DEBUG, ("VMS print status = %d\n", VMSstatus)); rv = WIFEXITED(VMSstatus) ? NS_OK : NS_ERROR_GFX_PRINTER_CMD_FAILURE; } } #else // On *nix, popen() the print command and pipe the contents of // mDocProlog into it. FILE *pipe; pipe = popen(mPrintSetup->print_cmd, "w"); if (!pipe) rv = NS_ERROR_GFX_PRINTER_CMD_FAILURE; else { unsigned long job_size = 0; /* Reset file pointer to the beginning of the temp file... */ fseek(mPrintSetup->out, 0, SEEK_SET); while ((length = fread(buffer, 1, sizeof(buffer), mPrintSetup->out)) > 0) { fwrite(buffer, 1, length, pipe); job_size += length; } fclose(mPrintSetup->out); PR_LOG(nsPostScriptObjLM, PR_LOG_DEBUG, ("piping done, copied %ld bytes.\n", job_size)); int exitStatus = pclose(pipe); rv = WIFEXITED(exitStatus) ? NS_OK : NS_ERROR_GFX_PRINTER_CMD_FAILURE; } mDocProlog->Remove(PR_FALSE); #endif } mPrintSetup->out = nsnull; mDocProlog = nsnull; return rv; } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc. Updated 3/22/2000 to deal with only non-Unicode chars. yueheng.xu@intel.com */ void nsPostScriptObj::show(const char* txt, int len, const char *align) { FILE *f; f = mPrintContext->prSetup->tmpBody; fprintf(f, "("); while (len-- > 0) { switch (*txt) { case '(': case ')': case '\\': fprintf(f, "\\%c", *txt); break; default: fprintf(f, "%c", *txt); break; } txt++; } fprintf(f, ") %sshow\n", align); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 6/1/2000 katakai */ void nsPostScriptObj::preshow(const PRUnichar* txt, int len) { FILE *f = mPrintContext->prSetup->tmpBody; unsigned char highbyte; PRUnichar uch; char outbuffer[6]; PRUnichar inbuffer[2]; nsresult res = NS_OK; if (gEncoder && gU2Ntable) { while (len-- > 0) { uch = *txt; highbyte = (uch >> 8 ) & 0xff; if (highbyte > 0) { inbuffer[0] = uch; inbuffer[1] = 0; PRInt32 *ncode = nsnull; nsStringKey key(inbuffer, 1); ncode = (PRInt32 *) gU2Ntable->Get(&key); if (ncode && *ncode) { } else { PRInt32 insize, outsize; outsize = 6; insize = 1; // example, 13327 (USC2 0x340f) -> 14913679 (gb18030 0xe3908f) res = gEncoder->Convert(inbuffer, &insize, outbuffer, &outsize); if (NS_SUCCEEDED(res) && outsize > 1) { int i; PRInt32 code = 0; for(i=1;i<=outsize;i++) { code += (outbuffer[i - 1] & 0xff) << (8 * (outsize - i)); } if (code) { ncode = new PRInt32; *ncode = code; gU2Ntable->Put(&key, ncode); fprintf(f, "%d <%x> u2nadd\n", uch, code); } } } } txt++; } } } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 3/22/2000 to deal with only unicode chars. yueheng.xu@intel.com */ void nsPostScriptObj::show(const PRUnichar* txt, int len, const char *align, int aType) { FILE *f = mPrintContext->prSetup->tmpBody; unsigned char highbyte, lowbyte; PRUnichar uch; if (aType == 1) { int i; fprintf(f, "<"); for (i=0; i < len; i++) { if (i == 0) fprintf(f, "%04x", txt[i]); else fprintf(f, " %04x", txt[i]); } fprintf(f, "> show\n"); return; } fprintf(f, "("); while (len-- > 0) { switch (*txt) { case 0x0028: // '(' fprintf(f, "\\050\\000"); break; case 0x0029: // ')' fprintf(f, "\\051\\000"); break; case 0x005c: // '\\' fprintf(f, "\\134\\000"); break; default: uch = *txt; highbyte = (uch >> 8 ) & 0xff; lowbyte = ( uch & 0xff ); // we output all unicode chars in the 2x3 digits oct format for easier post-processing // Our 'show' command will always treat the second 3 digit oct as high 8-bits of unicode, independent of Endians if ( lowbyte < 8 ) fprintf(f, "\\00%o", lowbyte & 0xff); else if ( lowbyte < 64 && lowbyte >= 8) fprintf(f, "\\0%o", lowbyte & 0xff); else fprintf(f, "\\%o", lowbyte & 0xff); if ( highbyte < 8 ) fprintf(f, "\\00%o", highbyte & 0xff); else if ( highbyte < 64 && highbyte >= 8) fprintf(f, "\\0%o", highbyte & 0xff); else fprintf(f, "\\%o", highbyte & 0xff); break; } txt++; } fprintf(f, ") %sunicodeshow\n", align); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::moveto(nscoord x, nscoord y) { fprintf(mPrintContext->prSetup->tmpBody, "%d %d moveto\n", x, y); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::lineto(nscoord aX, nscoord aY) { fprintf(mPrintContext->prSetup->tmpBody, "%d %d lineto\n", aX, aY); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @param aWidth Width of the ellipse implied by the arc * aHeight Height of the ellipse * aStartAngle Angle for the start of the arc * aEndAngle Angle for the end of the arc */ void nsPostScriptObj::arc(nscoord aWidth, nscoord aHeight, float aStartAngle,float aEndAngle) { // Arc definition fprintf(mPrintContext->prSetup->tmpBody, "%s %s matrix currentmatrix currentpoint translate\n" " 3 1 roll scale newpath 0 0 1 %s %s arc setmatrix\n", fpCString(aWidth * 0.5).get(), fpCString(aHeight * 0.5).get(), fpCString(aStartAngle).get(), fpCString(aEndAngle).get()); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::box(nscoord aX, nscoord aY, nscoord aW, nscoord aH) { fprintf(mPrintContext->prSetup->tmpBody, "%d %d %d %d Mrect ", aX, aY, aW, aH); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::box_subtract(nscoord aX, nscoord aY, nscoord aW, nscoord aH) { fprintf(mPrintContext->prSetup->tmpBody, "%d %d moveto 0 %d rlineto %d 0 rlineto 0 %d rlineto closepath ", aX, aY, aH, aW, -aH); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::clip() { fprintf(mPrintContext->prSetup->tmpBody, " clip \n"); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::eoclip() { fprintf(mPrintContext->prSetup->tmpBody, " eoclip \n"); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::clippath() { fprintf(mPrintContext->prSetup->tmpBody, " clippath \n"); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::newpath() { fprintf(mPrintContext->prSetup->tmpBody, " newpath \n"); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::closepath() { fprintf(mPrintContext->prSetup->tmpBody, " closepath \n"); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::initclip() { fprintf(mPrintContext->prSetup->tmpBody, " initclip \n"); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::line(nscoord aX1, nscoord aY1, nscoord aX2, nscoord aY2, nscoord aThick) { fprintf(mPrintContext->prSetup->tmpBody, "gsave %d setlinewidth\n ", aThick); fprintf(mPrintContext->prSetup->tmpBody, " %d %d moveto %d %d lineto\n", aX1, aY1, aX2, aY2); stroke(); fprintf(mPrintContext->prSetup->tmpBody, "grestore\n"); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::stroke() { fprintf(mPrintContext->prSetup->tmpBody, " stroke \n"); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::fill() { fprintf(mPrintContext->prSetup->tmpBody, " fill \n"); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::graphics_save() { fprintf(mPrintContext->prSetup->tmpBody, " gsave \n"); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::graphics_restore() { fprintf(mPrintContext->prSetup->tmpBody, " grestore \n"); } /** --------------------------------------------------- * Output postscript to scale the current coordinate system * @param aX X scale factor * aY Y scale factor */ void nsPostScriptObj::scale(float aX, float aY) { fprintf(mPrintContext->prSetup->tmpBody, "%s %s scale\n", fpCString(aX).get(), fpCString(aX).get()); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::translate(nscoord x, nscoord y) { fprintf(mPrintContext->prSetup->tmpBody, "%d %d translate\n", x, y); } /** --------------------------------------------------- * Draw an image. This involves two coordinate systems, one for the * page and one for the image. dRect is in the page coordinate system; * it describes the rectangle which the image should occupy on the page. * sRect describes the same rectangle, only in image space; it's the * portion of the image which should appear on the page. iRect describes * the position and dimensions of the actual pixel data within image * space. * * In the simple case, sRect and iRect will be the same, and their (x,y) * values will be (0,0). But images may have a virtual size larger than * the pixel rectangle, so iRect's position may not be (0,0) and its * dimensions may be smaller than sRect's. Similarly, it's possible that * only part of the image is being printed, in which case sRect's * position may not be (0,0) and its dimensions may not span the entire * iRect rectangle. So in the general case, iRect and sRect may be * completely arbitrary relative to each other and to the image-space * origin. * * @update 3/14/2004 kherron * @param anImage Image to draw * @param dRect Rectangle describing where on the page the image * should appear. Units are twips. * @param sRect Rectangle describing the portion of the image that * appears on the page, i.e. the part of the image's * coordinate space that maps to dRect. * @param iRect Rectangle describing the portion of the image's * coordinate space covered by the image pixel data. */ void nsPostScriptObj::draw_image(nsIImage *anImage, const nsRect& sRect, const nsRect& iRect, const nsRect& dRect) { FILE *f = mPrintContext->prSetup->tmpBody; // If a final image dimension is 0 pixels, just return (see bug 191684) if ((0 == dRect.width) || (0 == dRect.height)) { return; } anImage->LockImagePixels(PR_FALSE); PRUint8 *theBits = anImage->GetBits(); // Image data is unavailable, or it has no height or width. // There's nothing to print, so just return. if (!theBits || (0 == iRect.width) || (0 == iRect.height)) { anImage->UnlockImagePixels(PR_FALSE); return; } // Save the current graphic state and define a PS variable that // can hold one line of pixel data. fprintf(f, "gsave\n/rowdata %d string def\n", mPrintSetup->color ? iRect.width * 3 : iRect.width); // Translate the coordinate origin to the corner of the rectangle where // the image should appear, set up a clipping region, and scale the // coordinate system to the image's final size. translate(dRect.x, dRect.y); box(0, 0, dRect.width, dRect.height); clip(); fprintf(f, "%d %d scale\n", dRect.width, dRect.height); // Describe how the pixel data is to be interpreted: pixels per row, // rows, and bits per pixel (per component in color). fprintf(f, "%d %d 8 ", iRect.width, iRect.height); // Output the transformation matrix for the image. This is a bit tricky // to understand. PS image-drawing operations involve two transformation // matrices: (1) A Transformation matrix associated with the image // describes how to map the pixel data (width x height) onto a unit square, // and (2) the document's TM maps the unit square to the desired size and // position. The image TM is technically an inverse TM, i.e. it describes // how to map the unit square onto the pixel array. // // sRect and dRect define the same rectangle, only in different coordinate // systems. Following the translate & scale operations above, the origin // is at [sRect.x, sRect.y]. The "real" origin of image space is thus at // [-sRect.x, -sRect.y] and the pixel data should start at // [-sRect.x + iRect.x, -sRect.y + iRect.y]. These are negated because the // TM is supposed to be an inverse TM. nscoord tmTX = sRect.x - iRect.x; nscoord tmTY = sRect.y - iRect.y; // In document space, the target rectangle is [dRect.width, // dRect.height]; in image space it's [sRect.width, sRect.height]. So // the proper scale factor is [1/sRect.width, 1/sRect.height], but // again, the output should be an inverse TM so these are inverted. nscoord tmSX = sRect.width; nscoord tmSY = sRect.height; // If the image is being stretched and clipped, it's possible that only // a fraction of a pixel is supposed to be visible, resulting in a // dimension of zero after rounding. 0 isn't a valid scaling factor. // But something should appear on the page, unlike the case where dRect // or iRect is zero-sized, so force the dimension to 1. See bug 236801. if (0 == tmSX) tmSX = 1; if (0 == tmSY) tmSY = 1; // If the image data is in the wrong order, invert the TM, causing // the image to be drawn inverted. if (!anImage->GetIsRowOrderTopToBottom()) { tmTY += tmSY; tmSY = -tmSY; } fprintf(f, "[ %d 0 0 %d %d %d ]\n", tmSX, tmSY, tmTX, tmTY); // Output the data-reading procedure and the appropriate image command. fputs(" { currentfile rowdata readhexstring pop }", f); if (mPrintSetup->color) fputs(" false 3 colorimage\n", f); else fputs(" image\n", f); // Output the image data. The entire image is written, even // if it's partially clipped in the document. int outputCount = 0; PRInt32 bytesPerRow = anImage->GetLineStride(); for (nscoord y = 0; y < iRect.height; y++) { // calculate the starting point for this row of pixels PRUint8 *row = theBits // Pixel buffer start + y * bytesPerRow; // Rows already output for (nscoord x = 0; x < iRect.width; x++) { PRUint8 *pixel = row + (x * 3); if (mPrintSetup->color) outputCount += fprintf(f, "%02x%02x%02x", pixel[0], pixel[1], pixel[2]); else outputCount += fprintf(f, "%02x", NS_RGB_TO_GRAY(pixel[0], pixel[1], pixel[2])); if (outputCount >= 72) { fputc('\n', f); outputCount = 0; } } } anImage->UnlockImagePixels(PR_FALSE); // Free the PS data buffer and restore the previous graphics state. fputs("\n/rowdata where { /rowdata undef } if\n", f); fputs("grestore\n", f); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/99 dwc */ void nsPostScriptObj::setcolor(nscolor aColor) { float greyBrightness; /* For greyscale postscript, find the average brightness of red, green, and * blue. Using this average value as the brightness for red, green, and * blue is a simple way to make the postscript greyscale instead of color. */ if(mPrintSetup->color == PR_FALSE ) { greyBrightness=NS_PS_GRAY(NS_RGB_TO_GRAY(NS_GET_R(aColor), NS_GET_G(aColor), NS_GET_B(aColor))); fprintf(mPrintContext->prSetup->tmpBody, "%s setgray\n", fpCString(greyBrightness).get()); } else { fprintf(mPrintContext->prSetup->tmpBody, "%s %s %s setrgbcolor\n", fpCString(NS_PS_RED(aColor)).get(), fpCString(NS_PS_GREEN(aColor)).get(), fpCString(NS_PS_BLUE(aColor)).get()); } } void nsPostScriptObj::setfont(const nsCString aFontName, PRUint32 aHeight) { fprintf(mPrintContext->prSetup->tmpBody, "%d /%s Msf\n", aHeight, aFontName.get()); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/98 dwc */ void nsPostScriptObj::setscriptfont(PRInt16 aFontIndex,const nsString &aFamily,nscoord aHeight, PRUint8 aStyle, PRUint8 aVariant, PRUint16 aWeight, PRUint8 decorations) { int postscriptFont = 0; // fprintf(mPrintContext->prSetup->out, "%% aFontIndex = %d, Family = %s, aStyle = %d, // aWeight=%d, postscriptfont = %d\n", aFontIndex, &aFamily, aStyle, aWeight, postscriptFont); fprintf(mPrintContext->prSetup->tmpBody,"%d", aHeight); if( aFontIndex >= 0) { postscriptFont = aFontIndex; } else { //#ifdef NOTNOW //XXX:PS Add bold, italic and other settings here switch(aStyle){ case NS_FONT_STYLE_NORMAL : if (NS_IS_BOLD(aWeight)) { postscriptFont = 1; // TIMES NORMAL BOLD }else{ postscriptFont = 0; // Times ROMAN Normal } break; case NS_FONT_STYLE_ITALIC: if (NS_IS_BOLD(aWeight)) { postscriptFont = 2; // TIMES BOLD ITALIC }else{ postscriptFont = 3; // TIMES ITALIC } break; case NS_FONT_STYLE_OBLIQUE: if (NS_IS_BOLD(aWeight)) { postscriptFont = 6; // HELVETICA OBLIQUE }else{ postscriptFont = 7; // HELVETICA OBLIQUE } break; } //#endif } fprintf(mPrintContext->prSetup->tmpBody, " f%d\n", postscriptFont); #if 0 // The style of font (normal, italic, oblique) PRUint8 style; // The variant of the font (normal, small-caps) PRUint8 variant; // The weight of the font (0-999) PRUint16 weight; // The decorations on the font (underline, overline, // line-through). The decorations can be binary or'd together. PRUint8 decorations; // The size of the font, in nscoord units nscoord size; #endif } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 2/1/98 dwc */ void nsPostScriptObj::comment(const char *aTheComment) { fprintf(mPrintContext->prSetup->tmpBody,"%%%s\n", aTheComment); } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 5/30/00 katakai */ void nsPostScriptObj::setlanggroup(nsIAtom * aLangGroup) { FILE *f = mPrintContext->prSetup->tmpBody; gEncoder = nsnull; gU2Ntable = nsnull; if (aLangGroup == nsnull) { fprintf(f, "default_ls\n"); return; } nsAutoString langstr; aLangGroup->ToString(langstr); /* already exist */ nsStringKey key(langstr); PS_LangGroupInfo *linfo = (PS_LangGroupInfo *) gLangGroups->Get(&key); if (linfo) { nsCAutoString str; str.AssignWithConversion(langstr); fprintf(f, "%s_ls\n", str.get()); gEncoder = linfo->mEncoder; gU2Ntable = linfo->mU2Ntable; return; } else { fprintf(f, "default_ls\n"); } } PRBool nsPostScriptObj::GetUnixPrinterSetting(const nsCAutoString& aKey, char** aVal) { if (!mPrinterProps) { return nsnull; } nsAutoString oValue; nsresult res = mPrinterProps->GetStringProperty(aKey, oValue); if (NS_FAILED(res)) { return PR_FALSE; } *aVal = ToNewCString(oValue); return PR_TRUE; } typedef struct _unixPrinterFallbacks_t { const char *key; const char *val; } unixPrinterFallbacks_t; static const unixPrinterFallbacks_t unixPrinterFallbacks[] = { {"print.postscript.nativefont.ja", "Ryumin-Light-EUC-H"}, {"print.postscript.nativecode.ja", "euc-jp"}, {nsnull, nsnull} }; PRBool GetUnixPrinterFallbackSetting(const nsCAutoString& aKey, char** aVal) { const unixPrinterFallbacks_t *p; const char* key = aKey.get(); for (p=unixPrinterFallbacks; p->key; p++) { if (strcmp(key, p->key) == 0) { *aVal = nsCRT::strdup(p->val); return PR_TRUE; } } return PR_FALSE; } FILE * nsPostScriptObj::GetPrintFile() { return(mPrintContext->prSetup->out); } const char* kNativeFontPrefix = "print.postscript.nativefont."; const char* kUnicodeFontPrefix = "print.postscript.unicodefont."; /* make _ls define for each LangGroup here */ static void PrefEnumCallback(const char *aName, void *aClosure) { nsPostScriptObj *psObj = (nsPostScriptObj*)aClosure; FILE *f = psObj->GetPrintFile(); nsAutoString lang; lang.AssignWithConversion(aName); if (strstr(aName, kNativeFontPrefix)) { NS_ASSERTION(strlen(kNativeFontPrefix) == 28, "Wrong hard-coded size."); lang.Cut(0, 28); } else if (strstr(aName, kUnicodeFontPrefix)) { NS_ASSERTION(strlen(kNativeFontPrefix) == 29, "Wrong hard-coded size."); lang.Cut(0, 29); } nsStringKey key(lang); PS_LangGroupInfo *linfo = (PS_LangGroupInfo *) gLangGroups->Get(&key); if (linfo) { /* already exist */ return; } /* define new language group */ nsXPIDLCString psnativefont; nsXPIDLCString psnativecode; nsXPIDLCString psunicodefont; int psfontorder = 0; PRBool use_prefsfile = PR_FALSE; PRBool use_vendorfile = PR_FALSE; // // Try to get the info from the user's prefs file // nsCAutoString namepsnativefont(kNativeFontPrefix); namepsnativefont.AppendWithConversion(lang); gPrefs->CopyCharPref(namepsnativefont.get(), getter_Copies(psnativefont)); nsCAutoString namepsnativecode("print.postscript.nativecode."); namepsnativecode.AppendWithConversion(lang); gPrefs->CopyCharPref(namepsnativecode.get(), getter_Copies(psnativecode)); if (((psnativefont)&&(*psnativefont)) && ((psnativecode)&&(*psnativecode))) { use_prefsfile = PR_TRUE; } else { psnativefont.Adopt(0); psnativecode.Adopt(0); } // // if not found look for info from the printer vendor // if (use_prefsfile != PR_TRUE) { psObj->GetUnixPrinterSetting(namepsnativefont, getter_Copies(psnativefont)); psObj->GetUnixPrinterSetting(namepsnativecode, getter_Copies(psnativecode)); if ((psnativefont) && (psnativecode)) { use_vendorfile = PR_TRUE; } else { psnativefont.Adopt(0); psnativecode.Adopt(0); } } if (!use_prefsfile && !use_vendorfile) { GetUnixPrinterFallbackSetting(namepsnativefont, getter_Copies(psnativefont)); GetUnixPrinterFallbackSetting(namepsnativecode, getter_Copies(psnativecode)); } /* psnativefont and psnativecode both should be set */ if (!psnativefont || !psnativecode) { psnativefont.Adopt(0); psnativecode.Adopt(0); } else { nsCAutoString namepsfontorder("print.postscript.fontorder."); namepsfontorder.AppendWithConversion(lang); if (use_prefsfile) { gPrefs->GetIntPref(namepsfontorder.get(), &psfontorder); } else if (use_vendorfile) { nsXPIDLCString psfontorder_str; psObj->GetUnixPrinterSetting(namepsfontorder, getter_Copies(psfontorder_str)); if (psfontorder_str) { psfontorder = atoi(psfontorder_str); } } } /* check UCS fonts */ nsCAutoString namepsunicodefont(kUnicodeFontPrefix); namepsunicodefont.AppendWithConversion(lang); if (use_prefsfile) { gPrefs->CopyCharPref(namepsunicodefont.get(), getter_Copies(psunicodefont)); } else if (use_vendorfile) { psObj->GetUnixPrinterSetting(namepsunicodefont, getter_Copies(psunicodefont)); } nsresult res = NS_OK; if (psnativefont || psunicodefont) { linfo = new PS_LangGroupInfo; linfo->mEncoder = nsnull; linfo->mU2Ntable = nsnull; if (psnativecode) { nsAutoString str; nsCOMPtr ccMain = do_GetService(kCharsetConverterManagerCID, &res); if (NS_SUCCEEDED(res)) { res = ccMain->GetUnicodeEncoder(psnativecode.get(), &linfo->mEncoder); } } gLangGroups->Put(&key, (void *) linfo); nsCAutoString langstrC; langstrC.AssignWithConversion(lang); if (psnativefont && linfo->mEncoder) { fprintf(f, "/Unicode2NativeDict%s 0 dict def\n", langstrC.get()); } fprintf(f, "/%s_ls {\n", langstrC.get()); fprintf(f, " /NativeFont /%s def\n", (psnativefont && linfo->mEncoder) ? psnativefont.get() : "Courier"); fprintf(f, " /UCS2Font /%s def\n", psunicodefont ? psunicodefont.get() : "Courier"); if (psnativefont && linfo->mEncoder) { fprintf(f, " /Unicode2NativeDict Unicode2NativeDict%s def\n", langstrC.get()); } if (psfontorder) { fprintf(f, " /unicodeshow1 { real_unicodeshow_native } bind def\n"); fprintf(f, " /unicodeshow2 { real_unicodeshow } bind def\n"); } else { fprintf(f, " /unicodeshow1 { real_unicodeshow } bind def\n"); fprintf(f, " /unicodeshow2 { real_unicodeshow_native } bind def\n"); } fprintf(f, "} bind def\n"); if (linfo->mEncoder) { linfo->mEncoder->SetOutputErrorBehavior( linfo->mEncoder->kOnError_Replace, nsnull, '?'); linfo->mU2Ntable = new nsHashtable(); } } } /** --------------------------------------------------- * See documentation in nsPostScriptObj.h * @update 5/30/00 katakai */ void nsPostScriptObj::initlanggroup() { /* check langgroup of preference */ gPrefs->EnumerateChildren(kNativeFontPrefix, PrefEnumCallback, (void *) this); gPrefs->EnumerateChildren(kUnicodeFontPrefix, PrefEnumCallback, (void *) this); }