home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / modules / libfont / src / fb.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  23.8 KB  |  1,022 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.  * fb.cpp (FontBrokerObject.cpp)
  20.  *
  21.  * C++ implementation of the (fb) FontBrokerObject
  22.  *
  23.  * dp Suresh <dp@netscape.com>
  24.  */
  25.  
  26.  
  27. #include "fb.h"
  28.  
  29. // Since it creates these objects, it uses the local implementation of
  30. // Objects.
  31. // Create :    Font
  32. //            FontMatchInfo
  33. //            RenderingContext
  34. //            FontObserver
  35. #include "Mcf.h"
  36. #include "Pcf.h"
  37. #include "f.h"
  38. #include "Mcfmi.h"
  39. #include "Pcfmi.h"
  40. #include "fmi.h"
  41. #include "Mcrc.h"
  42. #include "Pcrc.h"
  43. #include "rc.h"
  44. #include "Pcdoer.h"
  45.  
  46. // Uses:    DoneObserver
  47. #include "Mnfdoer.h"
  48.  
  49. #include "net.h"        // libnet
  50. #ifndef NSPR20
  51. #include "prfile.h"        // for reading directories
  52. #else
  53. #include "prio.h"        // for reading directories
  54. #endif /* NSPR20 */
  55.  
  56. FontBrokerObject::
  57. FontBrokerObject() : fpPeers(NULL), fpPeersFromCatalog(NULL)
  58. {
  59.     // Enable webfonts by default
  60.     pref.enableWebfonts = 1;
  61. }
  62.  
  63. FontBrokerObject::
  64. ~FontBrokerObject()
  65. {
  66. }
  67.  
  68. //
  69. // FontBrokerConsumer Interface specific
  70. //
  71. struct nff * FontBrokerObject::
  72. LookupFont(struct nfrc *rc, struct nffmi *fmi, const char *accessor)
  73. {
  74.     struct nff *f = NULL;
  75.     
  76.     // Try to find a Font Object that we already created
  77.     // Wondering why the accessor is not involved in the match.
  78.     // All webfonts are NOT shared. Only local fonts are shared. And local
  79.     // fonts can be accessed by any accessor.
  80.     f = fontObjectCache.RcFmi2Font(rc, fmi);
  81.  
  82.     if (f)
  83.       {
  84.         WF_TRACEMSG(("NF: Found font object 0x%x for fmi (%s) in cache.",
  85.             f, nffmi_toString(fmi, NULL)));
  86.         return (f);
  87.       }
  88.  
  89.     // On each enabled FontDisplayer, do a LookupFont() and use the
  90.     // returned FontHandles to make a Font object.
  91.  
  92.     struct wfListElement *tmp = fpPeers.head;
  93.     for(; tmp; tmp = tmp->next)
  94.       {
  95.         FontDisplayerPeerObject *fpp = (FontDisplayerPeerObject *) tmp->item;
  96.         void *fh = NULL;
  97.         
  98.         //
  99.         // LookupFont() on a displayer will not be done if
  100.         //        displayer's catalog does not support the {rc, fmi}
  101.         //        and the displayer is not loaded.
  102.         // If the fpp was already loaded, ask it anyway.
  103.         // The logic is asking the catalog will save us from loading
  104.         // the fpp. But if the fpp is already loaded and in memory,
  105.         // then this operation is a relatively cheap operation. Webfonts
  106.         // rely on this. Once a font is streamed, anymore lookup fonts
  107.         // need to go the webfont displayer too as we dont know that facenames
  108.         // the streamed fron contains.
  109.         //
  110.         // *** The native displayer will always be asked.
  111.         //
  112.  
  113.         if (!fpp->isNative())
  114.         {
  115.             if (pref.enableWebfonts <= 0)
  116.             {
  117.                 // If webfonts are disabled, always believe the catalog.
  118.                 if (!fpp->queryCatalog(rc, fmi))
  119.                 {
  120.                     continue;
  121.                 }
  122.             }
  123.             else
  124.             {
  125.                 // If webfonts are enabled, then the special cases are
  126.                 // 1. fpp already loaded
  127.                 //        In this case, we always ask it. Catalog is not consulted.
  128.                 // 2. fpp gets loaded in the process of initializing the catalog
  129.                 //        In this case, we ask it since it got loaded.
  130.                 if (!fpp->isLoaded() && !fpp->queryCatalog(rc, fmi) && !fpp->isLoaded())
  131.                 {
  132.                     continue;
  133.                 }
  134.             }
  135.         }
  136.  
  137.         fh = fpp->LookupFont(rc, fmi, accessor);
  138.         if (fh)
  139.           {
  140.             if (!f)
  141.             {
  142.                 f = (struct nff *) cfFactory_Create(NULL, rc);
  143.                 if (!f)
  144.                 {
  145.                     // Error.
  146.                     return (NULL);
  147.                 }
  148.             }
  149.             cfImpl *fimpl = cf2cfImpl(f);
  150.             FontObject *fobj = (FontObject *)  fimpl->object;
  151.             
  152.             XP_ASSERT(fobj);
  153.             fobj->addFontHandle(fpp, fh);
  154.           }
  155.       }
  156.  
  157.     if (f)
  158.       {
  159.         WF_TRACEMSG(("NF: Created new font object 0x%x for fmi (%s).",
  160.             f, nffmi_toString(fmi, NULL)));
  161.         // The font needs to get added to the Font<-->Fmi map
  162.         // We have to do this as the font object cache is a central list of
  163.         // font objects.
  164.         fontObjectCache.add(fmi, f);
  165.       }
  166.     return (f);
  167. }
  168.  
  169.  
  170. struct nff *
  171. /*ARGSUSED*/
  172. FontBrokerObject::CreateFontFromUrl(struct nfrc* rc, const char* url_of_font,
  173.                                     const char *url_of_page, jint faux,
  174.                                     struct nfdoer* observer, MWContext *context)
  175. {
  176.     struct nff *f = NULL;
  177.  
  178.     // Decide if we want to pull the stream in
  179.     // We will not pull the stream under these conditions
  180.     // 1. webfonts is OFF in the preference
  181.     // 2. a font of this name was already created by us
  182.     
  183.     if (pref.enableWebfonts <= 0)
  184.     {
  185.         // webfonts is off. Dont do font streaming.
  186.         return (NULL);
  187.     }
  188.  
  189.     // We should not reuse webfonts. This is because a webfont created for
  190.     // one page should not be usable to another page according to
  191.     // webfont security. So we will always create these fresh.
  192.     
  193.     //
  194.     // Start a stream download of the url.
  195.     //
  196.     URL_Struct *url = NET_CreateURLStruct(url_of_font, NET_NORMAL_RELOAD);
  197.     if (!url)
  198.     {
  199.         // Error. Cannot create url struct.
  200.         WF_TRACEMSG(("NF: Error: Cannot create url struct."));
  201.         return (NULL);
  202.     }
  203.  
  204.     struct wf_new_stream_data *data = new wf_new_stream_data;
  205.     if (!data)
  206.     {
  207.         // Error. No memory to create wf_new_stream_data.
  208.         WF_TRACEMSG(("NF: Error: Cannot create wf_new_stream_data."));
  209.         NET_FreeURLStruct(url);
  210.         return (NULL);
  211.     }
  212.  
  213.     // Create a web FontObject
  214.     f = (struct nff *) cfFactory_Create(NULL, rc);
  215.     if (!f)
  216.     {
  217.         // Error.
  218.         WF_TRACEMSG(("NF: Error: Cannot create Font nff."));
  219.         NET_FreeURLStruct(url);
  220.         return (NULL);
  221.     }
  222.     // The fontobject that was created was wrong. We will destroy it and
  223.     // put a new correct fontobject
  224.     cfImpl *fimpl = cf2cfImpl(f);
  225.     FontObject *fobj = (FontObject *) fimpl->object;
  226.     delete fobj;
  227.     fobj = new FontObject(f, rc, url->address);
  228.     fimpl->object = fobj;
  229.  
  230.     nfdoer_addRef(observer, NULL);
  231.     data->observer = observer;
  232.     nff_addRef(f, NULL);
  233.     data->f = f;
  234.     nfrc_addRef(rc, NULL);
  235.     data->rc = rc;
  236.     data->url_of_page = CopyString(url_of_page);
  237.  
  238.     url->fe_data = data;
  239.  
  240.     //art NET_GetURL(url, FO_CACHE_AND_FONT, NULL, wfUrlExit);
  241.     NET_GetURL(url, FO_CACHE_AND_FONT, context,(Net_GetUrlExitFunc*) wfUrlExit);
  242.  
  243.     return (f);
  244. }
  245.  
  246. const char *
  247. FontBrokerObject::GetMimetype(const char *imimetype, const char *address)
  248. {
  249.     // If the mimetype was not known, we will try to figure out the mimetype
  250.     // from the extension. This is very tricky. We need to define two things:
  251.     // 1. How do we know the mimetype was not known. Let us declare that all
  252.     //        these mimetypes means the server doesn't know the mimetype
  253.     //            application/x-unknown
  254.     //            text/plain
  255.     //            text/html
  256.     //
  257.     // 2. What is the extension ?
  258.     //        We will define it as any string after the last dot in the url.
  259.     //        That means for http://www.nescape.com/a.tar.gz, we will only
  260.     //        recognize "gz" as the extension and not "tar.gz"
  261.     const char *mimetype = imimetype;
  262.     if (mimetype &&
  263.         (!wf_strcasecmp(mimetype, "text/plain") ||
  264.          !wf_strcasecmp(mimetype, "text/html") ||
  265.          !wf_strncasecmp(mimetype, "application/x-unknown", 21)))
  266.     {
  267.         mimetype = NULL;
  268.     }
  269.     if (!mimetype)
  270.     {
  271.         const char *extension = wf_getExtension(address);
  272.         struct wfListElement *tmp = fpPeers.head;
  273.         for(; tmp; tmp = tmp->next)
  274.         {
  275.             FontDisplayerPeerObject *fpp = (FontDisplayerPeerObject *) tmp->item;
  276.             mimetype = fpp->getMimetypeFromExtension(extension);
  277.             if (mimetype && *mimetype)
  278.             {
  279.                 break;
  280.             }
  281.         }
  282.         if (!mimetype)
  283.         {
  284.             // Noway of finding a mimetype for this url.
  285.             // Just use the original and see what happens.
  286.             mimetype = imimetype;
  287.         }
  288.     }
  289.     return (mimetype);
  290. }
  291.  
  292.  
  293. struct nff *
  294. /*ARGSUSED*/
  295. FontBrokerObject::CreateFontFromFile(struct nfrc* rc, const char *mimetype,
  296.                                      const char* fontFilename,
  297.                                      const char *url_of_page)
  298. {
  299.     // Decide if we want to pull the stream in
  300.     // We will not pull the stream under these conditions
  301.     // 1. webfonts is OFF in the preference
  302.     // 2. a font of this name was already created by us
  303.     
  304.     if (pref.enableWebfonts <= 0)
  305.     {
  306.         // webfonts is off. Dont do font streaming.
  307.         return (NULL);
  308.     }
  309.     struct nff *f = NULL;
  310.  
  311.     // We should not reuse webfonts. This is because a webfont created for
  312.     // one page should not be usable to another page according to
  313.     // webfont security. So we will always create these fresh.
  314.  
  315.     mimetype = GetMimetype(mimetype, fontFilename);
  316.     if (!mimetype || !*mimetype)
  317.     {
  318.         return (NULL);
  319.     }
  320.     
  321.     // Find which font Displayer implements the mimetype
  322.     struct wfListElement *tmp = fpPeers.head;
  323.     FontDisplayerPeerObject *fpp = NULL;
  324.     void *fh = NULL;
  325.     for(; tmp; tmp = tmp->next)
  326.     {
  327.         fpp = (FontDisplayerPeerObject *) tmp->item;
  328.         if (fpp->isMimetypeEnabled(mimetype) > 0 &&
  329.             (fh = fpp->CreateFontFromFile(rc, mimetype, fontFilename, url_of_page)))
  330.         {
  331.             f = (struct nff *) cfFactory_Create(NULL, rc);
  332.             if (!f)
  333.             {
  334.                 // Error.
  335.                 return (NULL);
  336.             }
  337.  
  338.             // The fontobject that was created was wrong. We will destroy it and
  339.             // put a new correct fontobject
  340.             cfImpl *fimpl = cf2cfImpl(f);
  341.             FontObject *fobj = (FontObject *) fimpl->object;
  342.             delete fobj;
  343.             fobj = new FontObject(f, rc, fontFilename);
  344.             fimpl->object = fobj;
  345.             
  346.             XP_ASSERT(fobj);
  347.             fobj->addFontHandle(fpp, fh);
  348.  
  349.             break;
  350.         }
  351.     }
  352.     return (f);
  353. }
  354.  
  355.  
  356. //
  357. // Ideally these catalog methods could be cached...
  358. //
  359. struct nffmi ** FontBrokerObject::
  360. ListFonts(struct nfrc *rc, struct nffmi *fmi)
  361. {
  362.     struct nffmi ** cumulativeFmiList = NULL;
  363.     int n = 0;
  364.     struct wfListElement *tmp = fpPeers.head;
  365.     for (; tmp; tmp = tmp->next)
  366.       {
  367.         FontDisplayerPeerObject *fpp = (FontDisplayerPeerObject *) tmp->item;
  368.         struct nffmi ** fmiList = fpp->ListFonts(rc, fmi);
  369.         if (fmiList && fmiList[0])
  370.           {
  371.             if (cumulativeFmiList == NULL)
  372.             {
  373.                 // This is the first time. Just initialize the
  374.                 // cumulativeFmiList with the fmiList.
  375.                 cumulativeFmiList = fmiList;
  376.                 while (fmiList[n]) n++;
  377.             }
  378.             else
  379.             {
  380.                 // Merge this list into the cumulativeFmiList
  381.                 merge(cumulativeFmiList, n, fmiList);
  382.  
  383.                 // WF_FREE is nffbu::free(). So this is ok.
  384.                 // We dont have to release each fmi as they have been
  385.                 // copied into the cumulativeFmiList
  386.                 WF_FREE(fmiList);}
  387.           }
  388.       }    
  389.     return(cumulativeFmiList);
  390. }
  391.  
  392.  
  393. jdouble * FontBrokerObject::
  394. ListSizes(struct nfrc *rc, struct nffmi *fmi)
  395. {
  396.     jdouble * cumulativeSizeList = NULL;
  397.     int maxSizes = 0;
  398.     struct wfListElement *tmp = fpPeers.head;
  399.     for (; tmp; tmp = tmp->next)
  400.       {
  401.         FontDisplayerPeerObject * fpp = (FontDisplayerPeerObject *) tmp->item;
  402.         jdouble* sizeList = fpp->ListSizes(rc, fmi);
  403.         if (sizeList && (sizeList[0] >= 0))
  404.           {
  405.             // Merge this list into the cumulativeFmiList
  406.             MergeSizes(cumulativeSizeList, maxSizes, sizeList);
  407.  
  408.             // WF_FREE is nffbu::free(). So this is ok.
  409.             WF_FREE(sizeList);
  410.           }
  411.       }    
  412.     return(cumulativeSizeList);
  413. }
  414.  
  415. /*ARGSUSED*/
  416. struct nff *
  417. FontBrokerObject::
  418. GetBaseFont(struct nfrf *rf)
  419. {
  420.     return(fontObjectCache.Rf2Font(rf));
  421. }
  422.  
  423. //
  424. // FontBrokerDisplayer interface specific
  425. //
  426. jint FontBrokerObject::
  427. RegisterFontDisplayer(struct nffp* fp)
  428. {
  429.     FontDisplayerPeerObject *fpp = new FontDisplayerPeerObject(fp);
  430.     return (registerDisplayer(fpp));
  431. }
  432.  
  433.  
  434. //
  435. // All displayer objects get created here. This checks the catalog and
  436. // creates displayer only if the dlm_name isn't in the catalog (or) the
  437. // dlm_name is newer than what we have in the catalog.
  438. //
  439. jint
  440. FontBrokerObject::
  441. CreateFontDisplayerFromDLM(const char* dlm_name)
  442. {
  443.     int ret = 0;
  444.     FontDisplayerPeerObject * fpp = NULL;
  445.     // Check the catalog to see if this dlm_name is present
  446.     struct wfListElement *tmp = fpPeersFromCatalog.head;
  447.     for (; tmp; tmp = tmp->next)
  448.     {
  449.         fpp = (FontDisplayerPeerObject *) tmp->item;
  450.         int dlmchanged = fpp->dlmChanged(dlm_name);
  451.         if (dlmchanged >= 0)
  452.         {
  453.             // Found the dlm in the catalog. Use it.
  454.             // 1. remove the fpp from the fpPeersFromCatalog list
  455.             fpPeersFromCatalog.remove(fpp);
  456.  
  457.             // 2. If the fpp has changed, resync it.
  458.             if (dlmchanged > 0)
  459.             {
  460.                 fpp->resync();
  461.             }
  462.             break;
  463.         }
  464.     }
  465.     
  466.     if (!tmp)
  467.     {
  468.         // Didn't find the dlm_name in the catalog. Create a new one.
  469.         fpp = new FontDisplayerPeerObject(dlm_name);
  470.     }
  471.  
  472.     // If the fpp was deleted, this dlm_name doesnt make a displayer
  473.     if (fpp->isDeleted())
  474.     {
  475.         delete fpp;
  476.         ret = -1;
  477.     }
  478.     else
  479.     {
  480.         ret = registerDisplayer(fpp);
  481.     }
  482.     return (ret);
  483. }
  484.  
  485.  
  486. #ifndef MAXPATHLEN
  487. #define MAXPATHLEN 1024
  488. #define WE_DEFINED_MAXPATHLEN
  489. #endif
  490.  
  491. jint FontBrokerObject::
  492. ScanForFontDisplayers(const char* dlmDirList)
  493. {
  494.     int ndisplayer = 0;
  495.     const char *str = dlmDirList;
  496.     char directoryName[MAXPATHLEN];
  497.     
  498.     while (*str != '\0')
  499.     {
  500.         str = wf_scanToken(str, directoryName, sizeof(directoryName), WF_PATH_SEP_STR, 0);
  501.  
  502.         wf_expandFilename(directoryName, MAXPATHLEN);
  503.  
  504.         if (directoryName[0] != '\0')
  505.         {
  506.             ndisplayer += scanDisplayersFromDir(directoryName);
  507.         }
  508.  
  509.         if (*str != '\0')
  510.         {
  511.             str++;
  512.         }
  513.     }
  514.     return (ndisplayer);
  515. }
  516.  
  517. int FontBrokerObject::scanDisplayersFromDir(const char *directoryName)
  518. {
  519.     int ndisplayer = 0;
  520.  
  521.     PRDir *dir;
  522.     PRDirEntry *dp;
  523.     char filename[MAXPATHLEN];
  524.     char *nameptr;
  525.  
  526.     if ((dir = PR_OpenDir(directoryName)) != NULL)
  527.     {
  528.         strcpy(filename, directoryName);
  529.         nameptr = &filename[strlen(filename)];
  530.         // The checking and addtion of '/' is OK on all platforms as the directoryName that
  531.         // NSPR uses is all unix style.
  532.         if (*(nameptr-1) != '/' )
  533.         {
  534.             *nameptr++ = '/';  
  535.         }
  536. #ifndef NSPR20
  537.         while ((dp = PR_ReadDir(dir, PR_SKIP_DOT | PR_SKIP_DOT_DOT)) != NULL)
  538. #else
  539.         while ((dp = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL)
  540. #endif
  541.         {
  542.             strcpy(nameptr, PR_DirName(dp));
  543.             if (wf_isFileDirectory(filename))
  544.             {
  545.                 ndisplayer += scanDisplayersFromDir(filename);
  546.             }
  547.             else if (wf_stringEndsWith(PR_DirName(dp), ".dll") ||
  548.                      wf_stringEndsWith(PR_DirName(dp), ".so") ||
  549.                      wf_stringEndsWith(PR_DirName(dp), ".sl") ||
  550.                      wf_stringEndsWith(PR_DirName(dp), ".dlm"))
  551.             {
  552.                 // Make a displayer out of this dll.
  553.                 jint ret = CreateFontDisplayerFromDLM(filename);
  554.                 if (ret >= 0)
  555.                 {
  556.                     ndisplayer++;
  557.                 }
  558.             }
  559.         }
  560.         PR_CloseDir(dir);
  561.     }
  562.     return (ndisplayer);
  563. }
  564.  
  565. #ifdef WE_DEFINED_MAXPATHLEN
  566. #undef MAXPATHLEN
  567. #undef WE_DEFINED_MAXPATHLEN
  568. #endif
  569.  
  570. void FontBrokerObject::
  571. RfDone(struct nfrf *rf)
  572. {
  573.     // Release all references to this rf in the Font
  574.     fontObjectCache.releaseRf(rf);
  575. }
  576.  
  577. //
  578. // FontBrokerUtility interface specific
  579. //  
  580. struct nffmi *
  581. FontBrokerObject::
  582. CreateFontMatchInfo(const char* name, const char* charset,
  583.                     const char* encoding, jint weight, jint pitch, jint style,
  584.                     jint underline, jint strikeOut,
  585.                     jint resX, jint resY)
  586. {
  587.     // XXX We should implement fmi cache here.
  588.     cfmi *fmi = cfmiFactory_Create(NULL, name, charset, encoding, weight,
  589.                                    pitch, style, underline, strikeOut, resX, resY);
  590.     return ((struct nffmi *) fmi);
  591. }
  592.  
  593. struct nfrc*
  594. FontBrokerObject::
  595. CreateRenderingContext(jint majorType, jint minorType,
  596.                        void **args, jsize nargs)
  597. {
  598.     // WARNING: Dont ever think about caching rc
  599.     crc *rc = crcFactory_Create(NULL, majorType, minorType, args, nargs);
  600.     return ((struct nfrc *) rc);
  601. }
  602.  
  603. struct nfdoer*
  604. FontBrokerObject::
  605. CreateFontObserver(nfFontObserverCallback callback, void *client_data)
  606. {
  607.     struct cdoer *doer = cdoerFactory_Create(NULL, callback, client_data);
  608.     return ((struct nfdoer *) doer);
  609. }
  610.  
  611. // Font preferences
  612.  
  613. jint
  614. FontBrokerObject::IsWebfontsEnabled(void)
  615. {
  616.     return (pref.enableWebfonts);
  617. }
  618.  
  619. jint
  620. FontBrokerObject::EnableWebfonts(void)
  621. {
  622.     pref.enableWebfonts = 1;
  623.     return (0);
  624. }
  625.  
  626. jint
  627. FontBrokerObject::DisableWebfonts(void)
  628. {
  629.     pref.enableWebfonts = 0;
  630.     return (0);
  631. }
  632.  
  633.  
  634. const char **
  635. FontBrokerObject::ListFontDisplayers()
  636. {
  637.     int ndisplayers = fpPeers.count();
  638.     if (ndisplayers <= 0)
  639.     {
  640.         return (NULL);
  641.     }
  642.  
  643.     const char **displayers =
  644.       (const char **) WF_ALLOC(sizeof(char *) * ndisplayers + 1);
  645.     if (!displayers)
  646.     {
  647.         // No memory
  648.         return (NULL);
  649.     }
  650.     
  651.     int i = 0;
  652.     struct wfListElement *tmp = fpPeers.head;
  653.     for (; tmp; tmp = tmp->next)
  654.     {
  655.         FontDisplayerPeerObject * fpp = (FontDisplayerPeerObject *) tmp->item;
  656.         if (fpp->name())
  657.         {
  658.             displayers[i++] = fpp->name();
  659.         }
  660.     }
  661.     displayers[i] = NULL;
  662.  
  663.     return (displayers);
  664. }
  665.  
  666. jint
  667. FontBrokerObject::IsFontDisplayerEnabled(const char *displayer)
  668. {
  669.     FontDisplayerPeerObject *fpp = findDisplayer(displayer);
  670.     if (!fpp)
  671.     {
  672.         return (-2);
  673.     }
  674.     return(fpp->isDisplayerEnabled());
  675. }
  676.  
  677. const char **
  678. FontBrokerObject::ListFontDisplayersForMimetype(const char *mimetype)
  679. {
  680.     int ndisplayers = fpPeers.count();
  681.     if (ndisplayers <= 0)
  682.     {
  683.         return (NULL);
  684.     }
  685.  
  686.     // 16 bit is unhappy to WF_FREE( const char **displayers )
  687.     char **displayersBuffer = (char **)WF_ALLOC(sizeof(char *) * ndisplayers + 1);
  688.     const char **displayers = (const char **)displayersBuffer;
  689.     if (!displayers)
  690.     {
  691.         // No memory
  692.         return (NULL);
  693.     }
  694.     
  695.     int i = 0;
  696.     struct wfListElement *tmp = fpPeers.head;
  697.     for (; tmp; tmp = tmp->next)
  698.     {
  699.         FontDisplayerPeerObject * fpp = (FontDisplayerPeerObject *) tmp->item;
  700.         if (fpp->isMimetypeEnabled(mimetype) > 0)
  701.         {
  702.             // this requests const char **displayers
  703.             if (fpp->name())
  704.             {
  705.                 displayers[i++] = fpp->name();
  706.             }
  707.         }
  708.     }
  709.     if (i == 0)
  710.     {
  711.         // There are no displayers that has this mimetype enabled.
  712.         WF_FREE(displayersBuffer);
  713.         displayers = NULL;
  714.     }
  715.     else
  716.     {
  717.         displayers[i] = NULL;
  718.     }
  719.  
  720.     return (displayers);
  721. }
  722.  
  723. const char *
  724. FontBrokerObject::FontDisplayerForMimetype(const char *mimetype)
  725. {
  726.     const char *displayer = NULL;
  727.     struct wfListElement *tmp = fpPeers.head;
  728.     // The first fpp which has this mimetype disabled
  729.     FontDisplayerPeerObject * first_fpp = NULL;
  730.     FontDisplayerPeerObject * fpp;
  731.     int ret;
  732.  
  733.     for (; tmp; tmp = tmp->next)
  734.     {
  735.         fpp = (FontDisplayerPeerObject *) tmp->item;
  736.         int ret = fpp->isMimetypeEnabled(mimetype);
  737.         if (ret > 0)
  738.         {
  739.             if (fpp->name())
  740.             {
  741.                 displayer = fpp->name();
  742.             }
  743.             break;
  744.         }
  745.         else if (!first_fpp && ret == 0)
  746.         {
  747.             first_fpp = fpp;
  748.         }
  749.     }
  750.     if (!displayer && first_fpp)
  751.     {
  752.         // No displayer has this mimetype enabled. Enable the first one.
  753.         ret = first_fpp->enableMimetype(mimetype);
  754.         if (ret >= 0)
  755.         {
  756.             displayer = first_fpp->name();
  757.         }
  758.         else
  759.         {
  760.             // The first fpp refused to enable this mimetype. Find more.
  761.             tmp = fpPeers.head;
  762.             for (; tmp; tmp = tmp->next)
  763.             {
  764.                 fpp = (FontDisplayerPeerObject *) tmp->item;
  765.                 int ret = fpp->isMimetypeEnabled(mimetype);
  766.                 if (ret == 0)
  767.                 {
  768.                     // Here is a font Displayer who has this mimetype disabled. Enable it.
  769.                     ret = fpp->enableMimetype(mimetype);
  770.                     if (ret >= 0)
  771.                     {
  772.                         // Success
  773.                         displayer = fpp->name();
  774.                         break;
  775.                     }
  776.                 }
  777.             }
  778.         }
  779.     }
  780.     return (displayer);
  781. }
  782.  
  783. jint
  784. FontBrokerObject::EnableFontDisplayer(const char *displayer)
  785. {
  786.     FontDisplayerPeerObject *fpp = findDisplayer(displayer);
  787.     if (!fpp)
  788.     {
  789.         return (-2);
  790.     }
  791.     return((jint)fpp->enableDisplayer());
  792. }
  793.  
  794. jint
  795. FontBrokerObject::DisableFontDisplayer(const char *displayer)
  796. {
  797.     FontDisplayerPeerObject *fpp = findDisplayer(displayer);
  798.     if (!fpp)
  799.     {
  800.         return (-2);
  801.     }
  802.     return((jint)fpp->disableDisplayer());
  803. }
  804.  
  805. jint
  806. FontBrokerObject::EnableMimetype(const char *displayer, const char *mimetype)
  807. {
  808.     int ret;
  809.     FontDisplayerPeerObject *fpp = findDisplayer(displayer);
  810.     if (!fpp)
  811.     {
  812.         // Displayer not found
  813.         ret = -2;
  814.     }
  815.     else if (fpp->enableMimetype(mimetype) < 0)
  816.     {
  817.         // Mimetype not in displayer.
  818.         ret = -1;
  819.     }
  820.     else
  821.     {
  822.         // Disable this mimetype for all other displayers
  823.         struct wfListElement *tmp = fpPeers.head;
  824.         for (; tmp; tmp = tmp->next)
  825.         {
  826.             FontDisplayerPeerObject * fpp = (FontDisplayerPeerObject *) tmp->item;
  827.             if (fpp->name() && strcmp(fpp->name(), displayer))
  828.             {
  829.                 fpp->disableMimetype(mimetype);
  830.             }
  831.         }
  832.         ret = 0;
  833.     }
  834.     return(ret);
  835. }
  836.  
  837. jint
  838. FontBrokerObject::DisableMimetype(const char *displayer, const char *mimetype)
  839. {
  840.     FontDisplayerPeerObject *fpp = findDisplayer(displayer);
  841.     if (!fpp)
  842.     {
  843.         // Displayer not found
  844.         return (-2);
  845.     }
  846.     return((jint)fpp->disableMimetype(mimetype));
  847. }
  848.  
  849.  
  850. jint
  851. FontBrokerObject::LoadCatalog(const char *filename)
  852. {
  853.     const char *catfile = filename;
  854.     if (!catfile || !*catfile)
  855.     {
  856.         catfile = catalogFilename;
  857.     }
  858.  
  859.     if (!catfile || !*catfile)
  860.     {
  861.         // Catalog file doens't exist
  862.         return (-1);
  863.     }
  864.  
  865.     // Read from the catalog file
  866.     FontCatalogFile fc(catfile);
  867.     if (fc.status() < 0)
  868.     {
  869.         return (-1);
  870.     }
  871.  
  872.     while (!fc.isEof())
  873.     {
  874.         FontDisplayerPeerObject * fpp = new FontDisplayerPeerObject (fc);
  875.         if (!fpp->isDeleted())
  876.         {
  877.             wfList::ERROR_CODE err = fpPeersFromCatalog.add(fpp);
  878.             if (err != wfList::SUCCESS)
  879.             {
  880.                 // Ignore this.
  881.                 delete fpp;
  882.             }
  883.         }
  884.         else
  885.         {
  886.             delete fpp;
  887.         }
  888.     }
  889.     return (0);    
  890. }
  891.  
  892. jint
  893. FontBrokerObject::SaveCatalog(const char *filename)
  894. {
  895.     const char *catfile = filename;
  896.     if (!catfile || !*catfile)
  897.     {
  898.         catfile = catalogFilename;
  899.     }
  900.  
  901.     if (!catfile || !*catfile)
  902.     {
  903.         // Catalog file doens't exist
  904.         return (-1);
  905.     }
  906.  
  907.     FontCatalogFile fc(catfile, 1 /* write */);
  908.  
  909.     if (fc.status() < 0)
  910.     {
  911.         return (-1);
  912.     }
  913.  
  914.     struct wfListElement *tmp = fpPeers.head;
  915.     while (tmp)
  916.     {
  917.         FontDisplayerPeerObject * fpp = (FontDisplayerPeerObject *) tmp->item;
  918.         fpp->describe(fc);
  919.         tmp = tmp->next;
  920.     }
  921.     return (0);    
  922. }
  923.  
  924. //
  925. // Private methods
  926. //
  927. FontDisplayerPeerObject *
  928. FontBrokerObject::findDisplayer(const char *displayerName)
  929. {
  930.     FontDisplayerPeerObject * wffpp = NULL;
  931.  
  932.     struct wfListElement *tmp = fpPeers.head;
  933.     for (; tmp; tmp = tmp->next)
  934.     {
  935.         FontDisplayerPeerObject * fpp = (FontDisplayerPeerObject *) tmp->item;
  936.         if (fpp->name() && !strcmp(fpp->name(), displayerName))
  937.         {
  938.             wffpp = fpp;
  939.             break;
  940.         }
  941.     }
  942.     return (wffpp);
  943. }
  944.  
  945. // Merge fmiList together
  946. int FontBrokerObject::
  947. merge(struct nffmi ** &srcList, int &srcLen,
  948.       struct nffmi **newList)
  949. {
  950.     int newlen = 0;
  951.     if (!newList || !newList[0])
  952.       {
  953.         return -1;
  954.       }
  955.  
  956.     while (newList[newlen]) newlen++;
  957.  
  958.     // Allocate more space to hold 
  959.     srcList = (struct nffmi **)
  960.       WF_REALLOC(srcList, sizeof(*srcList) * (srcLen + newlen + 1));
  961.     if (!srcList)
  962.       {
  963.         // No memory
  964.         return -1;
  965.       }
  966.  
  967.     //
  968.     // Copy the new list into the old one.
  969.     //
  970.     for(int i=0; i<newlen; i++)
  971.       {
  972.         srcList[srcLen+i] = newList[i];
  973.       }
  974.     srcLen += newlen;
  975.     srcList[srcLen] = NULL;
  976.  
  977.     return 0;
  978. }
  979.  
  980. jint FontBrokerObject::registerDisplayer(FontDisplayerPeerObject *fpp)
  981. {
  982.     //
  983.     // we need to make sure that the native displayer is added to the
  984.     // tail. The native displayer will be the last in the queue
  985.     // for asking for a font. Reason:
  986.     // - The native displayer might be implemented to always return
  987.     //   a font by doing a closest match.
  988.     //
  989.     FontDisplayerPeerObject *tmp_fpp;
  990.     wfList::ERROR_CODE err = fpPeers.add(fpp);
  991.     int ret = 0;
  992.     if (err != wfList::SUCCESS)
  993.     {
  994.         ret = -1;
  995.     }
  996.     else
  997.     {
  998.         // Reconfigure the fpPeers list so that the native
  999.         // displayer is at the end of the list.
  1000.         struct wfListElement *tmp = fpPeers.head;
  1001.         while(tmp)
  1002.         {
  1003.             tmp_fpp = (FontDisplayerPeerObject *) tmp->item;
  1004.             if (tmp_fpp->isNative())
  1005.             {
  1006.                 break;
  1007.             }
  1008.             tmp = tmp->next;
  1009.         }
  1010.         // Move native to the tail
  1011.         if (tmp && tmp != fpPeers.tail)
  1012.         {
  1013.             WF_TRACEMSG(("NF: Moving the native displayer to the end of the displayer list."));
  1014.             tmp_fpp = (FontDisplayerPeerObject *) tmp->item;
  1015.             fpPeers.remove((void *)tmp_fpp);
  1016.             // we are banking on the fact that add will add at end.
  1017.             fpPeers.add(tmp_fpp);
  1018.         }
  1019.     }
  1020.     return(ret);
  1021. }
  1022.