home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / gui / CFontReference.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  18.9 KB  |  792 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "CFontReference.h"
  20.  
  21. #include <Printing.h>
  22.  
  23. #include "uprefd.h"
  24. #include "xp_hash.h"
  25. #include "xp_mem.h"
  26. #include "lo_ele.h"
  27.  
  28. #include "FontTypes.h"
  29. #include "shist.h"
  30.  
  31. #include "resgui.h"
  32.  
  33. // Set this to 1 to force WebFont lookup instead of native font lookup
  34. #define TEST_NATIVE_DISPLAYER 0
  35.  
  36. #if TEST_NATIVE_DISPLAYER
  37. #include "mcfp.h"
  38. #endif
  39.  
  40. #include "libi18n.h"
  41. #include "UPropFontSwitcher.h"
  42. #include "UFixedFontSwitcher.h"
  43. #include "UUTF8TextHandler.h"
  44.  
  45. #define WEIGHT_BOLD 700
  46. #define WEIGHT_NORMAL 400     
  47.  
  48. class NameList
  49. {
  50. public:
  51.     NameList(char *list);
  52.     ~NameList();
  53.     
  54.     Boolean Empty();
  55.     void Next();
  56.     char *Current();
  57.     
  58. private:
  59.     char *list, *name;
  60.     int start, next;
  61. };
  62.  
  63. NameList::NameList(char *list)
  64. {
  65.     int length = strlen(list);
  66.     
  67.     this->list = list;
  68.     start = next = 0;
  69.     
  70.     
  71.     if (length > 0)
  72.     {
  73.         name = new char[length + 1];
  74.         this->Next();
  75.     }
  76.     else
  77.     {
  78.         name = NULL;
  79.     }
  80. }
  81.  
  82. NameList::~NameList()
  83. {
  84.     if (name != NULL)
  85.         delete[] name;
  86. }
  87.  
  88. char *NameList::Current()
  89. {
  90.     if (Empty())
  91.         return NULL;
  92.     
  93.     return name;
  94. }
  95.  
  96. Boolean NameList::Empty()
  97. {
  98.     return list == NULL || list[start] == '\0';
  99. }
  100.  
  101. void NameList::Next()
  102. {
  103.     start = next;
  104.     
  105.     if (Empty())
  106.         return;
  107.     
  108.     // skip over leading whitespace and commas to find the start of the name
  109.     while (list[start] != '\0' && (list[start] == ',' || isspace(list[start])))
  110.     {
  111.         start += 1;
  112.     }
  113.     
  114.     // find the end of the name
  115.     next = start;
  116.     while(list[next] != '\0' && list[next] != ',')
  117.     {
  118.         if (list[next] == '"' || list[next] == '\'')
  119.         {
  120.             char final = list[next];
  121.             
  122.             // find the matching quote
  123.             next += 1;
  124.             while (list[next] != '\0' && list[next] != final)
  125.             {
  126.                 next += 1;
  127.             }
  128.             
  129.             // if list[next] is null, there was no matching quote, so bail
  130.             if (list[next] == '\0')
  131.             {
  132.                 break;
  133.             }
  134.         }
  135.         
  136.         next += 1;
  137.     }
  138.     
  139.     // strip off trailing whitespace
  140.     int end = next - 1;
  141.     
  142.     while (end >= start && isspace(list[end]))
  143.     {
  144.         end -= 1;
  145.     }
  146.     
  147.     // copy what's between start and end into name
  148.     int src = start;
  149.     int dst = 0;
  150.     
  151.     // if it's quoted, strip off the quotes
  152.     if ((list[start] == '"' || list[start] == '\'') && list[end] == list[start])
  153.     {
  154.         src += 1;
  155.         end -= 1;
  156.     }
  157.     
  158.     // copy the characters from src to end into the name
  159.     while (src <= end)
  160.     {
  161.         name[dst++] = list[src++];
  162.     }
  163.     
  164.     name[dst] = '\0';
  165. }
  166.  
  167. void FE_ReleaseTextAttrFeData(MWContext * /* context */, LO_TextAttr *attr)
  168. {
  169.     CFontReference *fontReference = (CFontReference *) attr->FE_Data;
  170.     
  171.     if (fontReference != NULL)
  172.         delete fontReference;
  173. }
  174.  
  175. short CFontReference::GetScaledTextSize(short size, short attrSize)
  176. {
  177.     short scaledSize;
  178.     
  179.     if ( attrSize < 1 )
  180.         attrSize = 1;
  181.     else if ( attrSize > 7 )
  182.         attrSize = 7;
  183.     
  184.     // Ñ Houck's font table from WINFE
  185.     switch ( attrSize )
  186.     {
  187.         case 0: scaledSize =      size / 2   ; break;
  188.         case 1: scaledSize =  7 * size / 10  ; break;
  189.         case 2: scaledSize = 85 * size / 100 ; break;
  190.         case 3: scaledSize =      size       ; break;
  191.         case 4: scaledSize = 12 * size / 10  ; break;
  192.         case 5: scaledSize =  3 * size / 2   ; break;
  193.         case 6: scaledSize =  2 * size       ; break;
  194.         case 7: scaledSize =  3 * size       ; break;
  195.     }
  196.     
  197.     // should this test be at a higher level?
  198.     if ( scaledSize < 9 ) // looks bad at anything lower
  199.         scaledSize = 9;
  200.     
  201.     return scaledSize;
  202. }
  203.  
  204. CFontReference *CFontReference::GetFontReference(const CCharSet *charSet, LO_TextAttr* attr, MWContext *context, Boolean underlineLinks)
  205. {
  206.     CFontReference *result = NULL;
  207.     
  208.     if (attr->FE_Data != NULL)
  209.     {
  210.         result = (CFontReference *) attr->FE_Data;
  211.         
  212.         result->SynchToPort(qd.thePort);
  213.         
  214.         return result;
  215.     }
  216.  
  217.     for (NameList list(attr->font_face); !list.Empty(); list.Next())
  218.     {
  219.         
  220.         result = CWebFontReference::LookupWebFont(list.Current(), charSet, attr, context, underlineLinks);
  221.         
  222.         if (result != NULL)
  223.             goto cache_result;
  224.  
  225.         result = CNativeFontReference::LookupNativeFont(list.Current(), charSet, attr, underlineLinks);
  226.         
  227.         if (result != NULL)
  228.             goto cache_result;
  229.  
  230.         result = CNativeFontReference::LookupGenericFont(list.Current(), charSet, attr, underlineLinks);
  231.         
  232.         if (result != NULL)
  233.             goto cache_result;
  234.     }
  235.         
  236.         // if we get this far, we don't have any matching fonts
  237.         // just return the default font for the character set.
  238.     
  239.         short fontID;
  240.         
  241.         if ( attr->fontmask & LO_FONT_FIXED )
  242.             fontID = charSet->fFixedFontNum;
  243.         else
  244.             fontID = charSet->fPropFontNum;
  245.             
  246.         result =  new CNativeFontReference(fontID, charSet, attr, underlineLinks);
  247.  
  248. cache_result:        
  249.         attr->FE_Data = (void *) result;
  250.         return result;
  251. }
  252.      
  253. CFontReference::CFontReference(const CCharSet *charSet, const LO_TextAttr *attr)
  254. {
  255.     fIsGetFontInfoDirty = true;
  256.  
  257.     fMode = srcOr;
  258.     
  259.     if (attr->point_size == 0)
  260.     {
  261.         short textSize;
  262.         
  263.         if (attr->fontmask & LO_FONT_FIXED)
  264.             textSize = charSet->fFixedFontSize;
  265.         else
  266.             textSize = charSet->fPropFontSize;
  267.         
  268.         fSize = GetScaledTextSize(textSize, attr->size);
  269.     }
  270.     else
  271.     {
  272.         fSize = attr->point_size;
  273.     }
  274. }
  275.  
  276. CFontReference::~CFontReference()
  277. {
  278.     // **** is there anything to do here?
  279. }
  280.  
  281. void CNativeFontReference::Apply()
  282. {
  283.     if ( qd.thePort->txFont != fFont )
  284.         ::TextFont( fFont );
  285.         
  286.     if ( qd.thePort->txSize != fSize )
  287.         ::TextSize( fSize );
  288.         
  289.     if ( qd.thePort->txFace != fStyle )
  290.         ::TextFace( fStyle );
  291.         
  292.     if ( qd.thePort->txMode != fMode )
  293.         ::TextMode( fMode );
  294. }
  295.  
  296. CFontReference *CNativeFontReference::LookupNativeFont(char *fontName, const CCharSet *charSet, const LO_TextAttr *attr,
  297.         Boolean underlineLinks)
  298. {
  299.     short fontID;
  300.     CStr255 pName(fontName);
  301.     
  302.     ::GetFNum(pName, &fontID);
  303.     
  304.     if (fontID == 0)
  305.     {
  306.  
  307.     /*
  308.         Font ID 0 is the system font. Did we get this
  309.         ID because the named font doesn't exist, or
  310.         because we asked for the system font by name?
  311.     */    
  312.         static CStr255 systemFontName;
  313.         
  314.         if (systemFontName[0] == 0)
  315.             ::GetFontName(0, systemFontName);
  316.         
  317.         if (pName != systemFontName)
  318.             return NULL;
  319.     }
  320.     
  321.     return new CNativeFontReference(fontID, charSet, attr, underlineLinks);
  322. }
  323.  
  324. CFontReference *CNativeFontReference::LookupGenericFont(char *fontName, const CCharSet *charSet, const LO_TextAttr *attr,
  325.         Boolean underlineLinks)
  326. {
  327.     struct GenericFontFamily
  328.     {
  329.         char *genericName;
  330.         char *nativeName;
  331.     };
  332.     
  333.     // NOTE: These need to be in the same order as they are
  334.     // in the resource.
  335.     static GenericFontFamily genericNames[] =
  336.     {
  337.         {"serif",        NULL},
  338.         {"sans-serif",    NULL},
  339.         {"cursive",        NULL},
  340.         {"fantasy",        NULL},
  341.         {"monospace",    NULL}
  342.     };
  343.     
  344.     static const int genericNameCount = sizeof(genericNames) / sizeof(GenericFontFamily);
  345.     
  346.     for (int nameIndex = 0; nameIndex < genericNameCount; nameIndex += 1)
  347.     {
  348.         if (!XP_STRCASECMP(    fontName, genericNames[nameIndex].genericName))
  349.         {
  350.             if (genericNames[nameIndex].nativeName == NULL)
  351.             {
  352.                 Str255 nativeName;
  353.                 
  354.                 ::GetIndString(nativeName, GENERIC_FONT_NAMES_RESID, nameIndex + 1);
  355.                 
  356.                 XP_ASSERT(nativeName[0] != 0);
  357.                 
  358.                 // allocate memory for a copy of the name
  359.                 genericNames[nameIndex].nativeName = (char *) XP_ALLOC(nativeName[0] + 1);
  360.                 
  361.                 // bail if no memory for the name
  362.                 if (genericNames[nameIndex].nativeName == NULL)
  363.                     return NULL;
  364.                 
  365.                 // copy it as a C string    
  366.                 strncpy(genericNames[nameIndex].nativeName, (char *) &nativeName[1], nativeName[0]);
  367.                 genericNames[nameIndex].nativeName[nativeName[0]] = '\0';
  368.             }
  369.             
  370.             return CNativeFontReference::LookupNativeFont(genericNames[nameIndex].nativeName, charSet, attr, underlineLinks);
  371.         }
  372.     }
  373.     
  374.     return NULL;
  375. }
  376.  
  377. CNativeFontReference::CNativeFontReference(short font, const CCharSet *charSet, const LO_TextAttr *attr,
  378.         Boolean /* underlineLinks */) :
  379.         CFontReference(charSet, attr)
  380. {
  381.     fFont = font;
  382.     fStyle = 0;
  383.     
  384.     if ((charSet->fCSID & MULTIBYTE) != SINGLEBYTE)
  385.     {
  386.         switch(charSet->fCSID)
  387.         {
  388.         case CS_UTF8:
  389.             fTextHandler = UUTF8TextHandler::Instance();
  390.             break;
  391.     
  392.     /*
  393.         // **** really want handlers for all multi-byte text
  394.         // use system for now...
  395.         case CS_SJIS:
  396.             fTextHandler = SJISTextHandler::Instance();
  397.             break;
  398.         
  399.         default:
  400.             fTextHandler = MBTextHandler::Instance();
  401.     */
  402.         default:
  403.             fTextHandler = NULL;
  404.         }
  405.         
  406.         if (attr->fontmask & LO_FONT_FIXED)
  407.             fFontSwitcher = UFixedFontSwitcher::Instance();
  408.         else
  409.             fFontSwitcher = UPropFontSwitcher::Instance();
  410.     }
  411.     else
  412.     {
  413.         fTextHandler = NULL;
  414.         fFontSwitcher = NULL;
  415.     }
  416.     
  417.     if (attr->font_weight >= WEIGHT_BOLD || (attr->fontmask & LO_FONT_BOLD) != 0)
  418.         fStyle |= bold;
  419.     
  420.     if (attr->fontmask & LO_FONT_ITALIC)
  421.         fStyle |= italic;
  422.     
  423.     if (attr->attrmask & LO_ATTR_UNDERLINE)
  424.         fStyle |= underline;
  425. }
  426.  
  427. CNativeFontReference::~CNativeFontReference()
  428. {
  429.     // **** Anything interesting to do here?
  430. }
  431.  
  432. void CNativeFontReference::DrawText(int x, int y, char *text, int start, int end)
  433. {
  434.     ::MoveTo(x, y);
  435.     
  436.     if (fTextHandler != NULL)
  437.         fTextHandler->DrawText(fFontSwitcher, &text[start], end - start + 1);
  438.     else
  439.         ::DrawText(text, start, end - start + 1);
  440.     
  441. }
  442.  
  443. short CNativeFontReference::TextWidth(char *text, int firstByte, int byteCount)
  444. {
  445.     if (fTextHandler != NULL)
  446.         return fTextHandler->TextWidth(fFontSwitcher, &text[firstByte], byteCount);
  447.     else
  448.         return ::TextWidth(text, firstByte, byteCount);
  449. }
  450.  
  451. short CNativeFontReference::MeasureText(char *text, int firstByte, int byteCount, short* charLocs)
  452. {
  453.     if (fTextHandler != NULL)
  454.         return 0;
  455.     else
  456.     {
  457.         text = &text[firstByte];
  458.         ::MeasureText(byteCount, text, charLocs);
  459.  
  460.         // remove null chars widths
  461.         short widthOffset = 0;
  462.         short nullCharWidth = 0;
  463.         for (int i = 1; i <= byteCount; i ++)
  464.         {
  465.             if (text[i-1] == '\0')
  466.             {
  467.                 if (nullCharWidth == 0)
  468.                 {
  469.                     nullCharWidth = charLocs[i] - charLocs[i-1];
  470.                     if (nullCharWidth == 0)
  471.                         break;
  472.                 }
  473.                 widthOffset += nullCharWidth;
  474.             }
  475.             charLocs[i] -= widthOffset;
  476.         }
  477.  
  478.         return byteCount;
  479.     }
  480. }
  481.  
  482. void CNativeFontReference::GetFontInfo(FontInfo *fontInfo)
  483. {
  484.     if (fIsGetFontInfoDirty)
  485.     {
  486.         if (fTextHandler != NULL)
  487.             fTextHandler->GetFontInfo(fFontSwitcher, &fCachedFontInfoValues);
  488.         else
  489.             ::GetFontInfo(&fCachedFontInfoValues);
  490.             
  491.         fIsGetFontInfoDirty = false;
  492.     }
  493.     
  494.     *fontInfo = fCachedFontInfoValues;
  495. }
  496.  
  497. FontBrokerHandle CWebFontReference::sBroker = NULL;
  498. FontBrokerUtilityHandle CWebFontReference::sUtility = NULL;
  499. XP_HashTable CWebFontReference::sPortHash = NULL;
  500.  
  501. char *CWebFontReference::sCatalogPath = NULL;
  502.  
  503. #define REQUIRED_GUTS_PATH "/usr/local/netscape/RequiredGuts/"
  504.  
  505. void CWebFontReference::Init()
  506. {
  507.     jint jresult;
  508.     char *displayerPath;
  509.     Str31 essentialFiles, dynamicFonts, dynamicFontCatalog;
  510.     FontBrokerDisplayerHandle brokerDisplayer;
  511. #if TEST_NATIVE_DISPLAYER
  512.     FontDisplayerHandle nativeDisplayer;
  513. #endif
  514.     
  515.     sPortHash = XP_HashTableNew(10, PortHash, PortCompFunction);
  516.     
  517.     sBroker = NF_FontBrokerInitialize();
  518.     if (sBroker == NULL)
  519.     {
  520.         // error?
  521.         return;
  522.     }
  523.     
  524.     brokerDisplayer = (FontBrokerDisplayerHandle) nffbc_getInterface(sBroker, &nffbp_ID, NULL);
  525.     if(brokerDisplayer == NULL)
  526.     {
  527.         // error?
  528.         return;
  529.     }
  530.     
  531. #if TEST_NATIVE_DISPLAYER
  532.     nativeDisplayer = (FontDisplayerHandle) cfpFactory_Create(NULL, brokerDisplayer);
  533.     if (nativeDisplayer != NULL)
  534.     {
  535.         nffbp_RegisterFontDisplayer(brokerDisplayer, nativeDisplayer, NULL);
  536.     }
  537. #endif
  538.  
  539.     sUtility = (FontBrokerUtilityHandle) nffbc_getInterface(sBroker, &nffbu_ID, NULL);
  540.     if (sUtility == NULL)
  541.     {
  542.         // error?
  543.         return;
  544.     }
  545.     
  546.     ::GetIndString(essentialFiles, 14000, 1);
  547.     ::GetIndString(dynamicFonts, 14000, 3);
  548.     ::GetIndString(dynamicFontCatalog, 14000, 4);
  549.     
  550.     XP_ASSERT(essentialFiles[0] != 0 && dynamicFonts[0] != 0 && dynamicFontCatalog[0] != 0);
  551.     
  552.     // "+ 4" is for three colons plus the null
  553.     sCatalogPath = (char *) XP_ALLOC(essentialFiles[0] + dynamicFonts[0] + dynamicFontCatalog[0] + 4);
  554.     if (sCatalogPath != NULL)
  555.     {
  556.         // Build ":Essential Files:DynamicFonts:Dynamic Font Catalog"
  557.         strcpy(sCatalogPath, PATH_SEPARATOR_STR);
  558.         strncat(sCatalogPath, (char *) &essentialFiles[1], essentialFiles[0]);
  559.         strcat(sCatalogPath, PATH_SEPARATOR_STR);
  560.         strncat(sCatalogPath, (char *) &dynamicFonts[1], dynamicFonts[0]);
  561.         strcat(sCatalogPath, PATH_SEPARATOR_STR);
  562.         strncat(sCatalogPath, (char *) &dynamicFontCatalog[1], dynamicFontCatalog[0]);
  563.     
  564.         // Don't care if this fails, file will be created when we save it.
  565.         jresult = nffbu_LoadCatalog(sUtility, sCatalogPath, NULL);
  566.     }
  567.     
  568.     // "+ 2" is for one slash and the null    
  569.     displayerPath = (char *) XP_ALLOC(sizeof(REQUIRED_GUTS_PATH) + dynamicFonts[0] + 2);
  570.     if (displayerPath != NULL)
  571.     {
  572.         // Build REQUIRED_GUTS_PATH "Dynamic Fonts/"
  573.         strcpy(displayerPath, REQUIRED_GUTS_PATH);
  574.         strncat(displayerPath, (char *) &dynamicFonts[1], dynamicFonts[0]);
  575.         strcat(displayerPath, DIRECTORY_SEPARATOR_STR);
  576.  
  577.         // Result is number of displayers created, we don't really care
  578.         jresult = nffbp_ScanForFontDisplayers(brokerDisplayer, displayerPath, NULL);
  579.         
  580.         XP_FREE(displayerPath);
  581.     }
  582. }
  583.  
  584. void CWebFontReference::Finish()
  585. {
  586.     jint result;
  587.     
  588.     if (sCatalogPath != NULL)
  589.     {
  590.         result = nffbu_SaveCatalog(sUtility, sCatalogPath, NULL);
  591.         XP_FREE(sCatalogPath);
  592.         sCatalogPath = NULL;
  593.     }
  594. }
  595.  
  596. // Make sure the rc's port is port...
  597. void CWebFontReference::SynchToPort(GrafPtr port)
  598. {
  599.     struct rc_data rcd = nfrc_GetPlatformData(fRenderingContext, NULL);
  600.     
  601.     if (rcd.t.directRc.port != port)
  602.     {
  603.         rcd.t.directRc.port = port;
  604.         nfrc_SetPlatformData(fRenderingContext, &rcd, NULL);
  605.     }
  606.     
  607. }
  608.  
  609. // It's not clear to me that this is good hash, but it's fast!
  610. uint32 CWebFontReference::PortHash(const void *port)
  611. {
  612.     return (uint32) port;
  613. }
  614.  
  615. // Should I look at the port fields if the addresses aren't equal?
  616. int CWebFontReference::PortCompFunction(const void *port1, const void *port2)
  617. {
  618.     return port1 != port2;
  619. }
  620.  
  621. RenderingContextHandle CWebFontReference::GetCachedRenderingContext(GrafPtr port)
  622. {
  623.     RenderingContextHandle rc = (RenderingContextHandle) XP_Gethash(sPortHash, port, NULL);
  624.     
  625.     if (rc == NULL)
  626.     {
  627.         void *rcArgs[1];
  628.         
  629.         rcArgs[0] = port;
  630.         rc = nffbu_CreateRenderingContext(sUtility, NF_RC_DIRECT, 0, rcArgs, 1, NULL);
  631.         
  632.         if (rc != NULL)
  633.         {
  634.             XP_Puthash(sPortHash, port, rc);
  635.         }
  636.         // error?
  637.     }
  638.     
  639.     return rc;
  640. }
  641.     
  642. CFontReference *CWebFontReference::LookupWebFont(char *fontName, const CCharSet *charSet, const LO_TextAttr *attr, MWContext *context, Boolean underlineLinks)
  643. {
  644.     FontMatchInfoHandle fmi;
  645.     RenderingContextHandle renderingContext;
  646.     WebFontHandle webFont;
  647.     
  648.     char        encoding[64];            // Should get the "64" from a header file...
  649.     char        *charset = NULL;        // Is this the right value?
  650.     int            weight;
  651.     int            style = nfStyleNormal;
  652.     int            escapement = nfSpacingProportional;
  653.     int            underline = nfUnderlineNo;
  654.     int            strikeout = nfStrikeOutNo;
  655.     int            resolutionX, resolutionY;
  656.  
  657.     if (attr->font_weight != 0)
  658.         weight = attr->font_weight;
  659.     else if (attr->fontmask & LO_FONT_BOLD)
  660.         weight = WEIGHT_BOLD;
  661.     else
  662.         weight = WEIGHT_NORMAL;
  663.  
  664.     if (attr->fontmask & LO_FONT_ITALIC)
  665.         style = nfStyleItalic;
  666.     
  667.     if (attr->fontmask & LO_FONT_FIXED)
  668.         escapement = nfSpacingMonospaced;
  669.     
  670.     if (attr->attrmask & LO_ATTR_UNDERLINE)
  671.         underline = nfUnderlineYes;
  672.     
  673.     if ((attr->attrmask & LO_ATTR_ANCHOR) != 0 && underlineLinks)
  674.         underline = nfUnderlineYes;
  675.     
  676.     if (attr->attrmask & LO_ATTR_STRIKEOUT)
  677.         strikeout = nfStrikeOutYes;
  678.     
  679.     if (context->type == MWContextPrint)
  680.     {
  681.         THPrint hp = CPrefs::GetPrintRecord();
  682.         
  683.         if (hp != NULL)
  684.         {
  685.             ::PrValidate(hp);
  686.         
  687.             resolutionX = (**hp).prInfo.iHRes;
  688.             resolutionY = (**hp).prInfo.iVRes;
  689.         }
  690.         else
  691.         {
  692.             // **** What is a good default in this case?
  693.             resolutionX = 72;
  694.             resolutionY = 72;
  695.         }
  696.     }
  697.     else
  698.     {
  699.         resolutionX = context->XpixelsPerPoint * 72.0;
  700.         resolutionY = context->YpixelsPerPoint * 72.0;
  701.     }
  702.     
  703.     INTL_CharSetIDToName(charSet->fCSID, encoding);
  704.     
  705.     fmi = nffbu_CreateFontMatchInfo(sUtility, fontName, charset, encoding,
  706.                 weight, escapement, style, underline, strikeout,
  707.                 resolutionX, resolutionY,
  708.                 NULL);
  709.     
  710.     if (fmi == NULL)
  711.     {
  712.         // if we can't get an fmi, just bail
  713.         return NULL;
  714.     }
  715.     
  716.     // **** Is qd.thePort the right place to get the port from?
  717.     History_entry *he = SHIST_GetCurrent(&context->hist);
  718.     char *url = NULL;
  719.     
  720.     if (he != NULL)
  721.         url = he->address;
  722.             
  723.     renderingContext = GetCachedRenderingContext(qd.thePort);
  724.     webFont = nffbc_LookupFont(sBroker, renderingContext, fmi, url, NULL);
  725.     
  726.     if (webFont == NULL)
  727.     {
  728.         nffbu_LookupFailed(sUtility, context, renderingContext, fmi, NULL);
  729.         nffmi_release(fmi, NULL);
  730.         
  731.         return NULL;
  732.     }
  733.     
  734.     return new CWebFontReference(webFont, charSet, attr);
  735. }
  736.     
  737. CWebFontReference::CWebFontReference(WebFontHandle webFont, const CCharSet *charSet, const LO_TextAttr *attr) :
  738.             CFontReference(charSet, attr)
  739. {
  740.     fRenderingContext = GetCachedRenderingContext(qd.thePort);
  741.     fRenderableFont = nff_GetRenderableFont(webFont, fRenderingContext, fSize, NULL);
  742.     
  743.     nff_release(webFont, NULL);
  744. }
  745.  
  746. CWebFontReference::~CWebFontReference()
  747. {
  748.     nfrf_release(fRenderableFont, NULL);
  749. }
  750.  
  751. void CWebFontReference::Apply()
  752. {
  753.     if ( qd.thePort->txMode != fMode )
  754.         ::TextMode( fMode );
  755. }
  756.  
  757. void CWebFontReference::DrawText(int x, int y, char *text, int start, int end)
  758. {
  759.     nfrf_DrawText(fRenderableFont, fRenderingContext, x, y, 0, &text[start], end - start + 1, NULL);
  760. }
  761.  
  762. short CWebFontReference::TextWidth(char *text, int firstByte, int byteCount)
  763. {
  764.     jint totalLength;
  765.     jint *charLocs;
  766.     
  767.     // **** Do we need to calculate the character count here?
  768.     charLocs = (jint *) XP_ALLOC(byteCount * sizeof(jint));
  769.     
  770.     totalLength = nfrf_MeasureText(fRenderableFont, fRenderingContext, 0, &text[firstByte], byteCount, charLocs, byteCount, NULL);
  771.  
  772.     XP_FREE(charLocs);
  773.     return (short) totalLength;
  774. }
  775.  
  776. void CWebFontReference::GetFontInfo(FontInfo *fontInfo)
  777. {
  778.     if (fIsGetFontInfoDirty)
  779.     {
  780.         fCachedFontInfoValues.ascent = nfrf_GetFontAscent(fRenderableFont, NULL);
  781.         fCachedFontInfoValues.descent = nfrf_GetFontDescent(fRenderableFont, NULL);
  782.         fCachedFontInfoValues.widMax = nfrf_GetMaxWidth(fRenderableFont, NULL);
  783.         
  784.         // **** Can we do better here?
  785.         fontInfo->leading = 0;
  786.         
  787.         fIsGetFontInfoDirty = false;
  788.     }
  789.     
  790.     *fontInfo = fCachedFontInfoValues;
  791. }
  792.