/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla 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/MPL/ * * 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 the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * wffppeer.cpp (FontDisplayerPeerObject.cpp) * * This object is local to the FontDisplayer. One of these objects * exist for every FontDisplayer that exists. All calls to the FontDisplayer * are routed through this peer object. This takes care of loading and * unloading the FontDisplayers as neccessary. * * dp Suresh */ #include "wffpPeer.h" #include "fe_proto.h" #define WF_ONE_MILLESEC 1 #define WF_ONE_MINUTE (60 * 1000 * WF_ONE_MILLESEC) /* Getting intl string ids */ #define WANT_ENUM_STRING_IDS #include "allxpstr.h" #undef WANT_ENUM_STRING_IDS FontDisplayerPeerObject:: FontDisplayerPeerObject(struct nffp *fp) : dlm(NULL), deleted(0), disabled(0), native(-1), streamCount(0), fhList(NULL), unloadTimerId(NULL) { XP_ASSERT(fp); fpType = FontDisplayerPeerObject::WF_FP_STATIC; fontDisplayer = fp; // Although there we aren't expected to free the returned // Name and Description, we could unload this dynamic modules // and the name and decription could be in their data space. // So to prevent losing these, we take a copy. displayerName = CopyString(nffp_Name(fontDisplayer, NULL)); displayerDescription = CopyString(nffp_Description(fontDisplayer, NULL)); #if defined(XP_WIN) && !defined(WIN32) // Win16 It seems the const char * assignment doesn't work. char mimeString[256]; *mimeString = '\0'; strcpy(mimeString, nffp_EnumerateMimeTypes(fontDisplayer, NULL)); #else const char *mimeString = nffp_EnumerateMimeTypes(fontDisplayer, NULL); #endif if (mimeString && *mimeString ) { mimeList.reconstruct(mimeString); registerConverters(); } } FontDisplayerPeerObject:: FontDisplayerPeerObject(const char *dlmName) : dlm(dlmName), mimeList(NULL), deleted(0), disabled(0), native(-1), streamCount(0), fhList(NULL), unloadTimerId(NULL) { fpType = FontDisplayerPeerObject::WF_FP_DYNAMIC; fontDisplayer = NULL; displayerName = NULL; displayerDescription = NULL; if (dlm.status() < 0) { deleted = 1; return; } #ifdef DEBUG // Don't load in purified versions of libraries. if(XP_STRSTR(dlmName, "_pure_")) { XP_ASSERT(0); deleted = 1; return; } #endif if (load() < 0) { deleted = 1; return; } displayerName = CopyString(nffp_Name(fontDisplayer, NULL)); displayerDescription = CopyString(nffp_Description(fontDisplayer,NULL)); #if defined(XP_WIN) && !defined(WIN32) // Win16 It seems the const char * assignment doesn't work. char mimeString[256]; *mimeString = '\0'; strcpy(mimeString, nffp_EnumerateMimeTypes(fontDisplayer, NULL)); #else const char *mimeString = nffp_EnumerateMimeTypes(fontDisplayer, NULL); #endif if (mimeString && *mimeString ) { mimeList.reconstruct(mimeString); registerConverters(); } } FontDisplayerPeerObject:: FontDisplayerPeerObject(FontCatalogFile &fc) : dlm(NULL), deleted(0), disabled(0), native(-1), streamCount(0), fhList(NULL), unloadTimerId(NULL) { fpType = FontDisplayerPeerObject::WF_FP_DYNAMIC; fontDisplayer = NULL; displayerName = NULL; displayerDescription = NULL; reconstruct(fc); } FontDisplayerPeerObject:: ~FontDisplayerPeerObject() { finalize(); } jint FontDisplayerPeerObject:: describe(FontCatalogFile &fc) { char *s; // Print out the displayer information if (fpType != WF_FP_DYNAMIC) { return (0); } fc.output("displayer = {"); fc.indentIn(); s = "dynamic"; fc.output("type", s); s = dlm.describe(); fc.output("dlm", s); if (s) { XP_FREE(s); } fc.output("name", displayerName); fc.output("description", displayerDescription); s = mimeList.describe(); fc.output("mimeString", s); if (s) { XP_FREE(s); } fc.output("deleted", deleted); fc.output("disabled", disabled); fc.output("catalog = {"); fc.indentIn(); catalog.describe(fc); fc.indentOut(); fc.output("} // End of catalog"); fc.indentOut(); fc.output("} // End of displayer"); return (0); } jint FontDisplayerPeerObject:: reconstruct(FontCatalogFile &fc) { char buf[1024]; int buflen; int over = 0; char *variable = NULL; char *value = NULL; char *ret; finalize(); while (!over) { ret = fc.readline(buf, sizeof(buf)); if (!ret) { over = 1; continue; } buflen = strlen((const char *)buf); if (buf[buflen-1] == '\n') { buf[buflen-1] = '\0'; buflen--; } if (!strncmp(buf, "#", 1)) { // Ignore comments continue; } wf_scanVariableAndValue(buf, buflen, variable, value); if (!wf_strcasecmp(variable, "displayer")) { continue; } else if (!wf_strcasecmp(variable, "type")) { if (!wf_strcasecmp(value, "dynamic")) { fpType = WF_FP_DYNAMIC; } else { deleted = 1; over = 1; continue; } } else if (!wf_strcasecmp(variable, "dlm")) { fontDisplayer = NULL; dlm.reconstruct(value); if (dlm.status() < 0) { deleted = 1; over = 1; continue; } } else if (!wf_strcasecmp(variable, "disabled")) { disabled = atoi(value); } else if (!wf_strcasecmp(variable, "name")) { if (displayerName) delete displayerName; displayerName = CopyString(value); } else if (!wf_strcasecmp(variable, "description")) { if (displayerDescription) delete displayerDescription; displayerDescription = CopyString(value); } else if (!wf_strcasecmp(variable, "mimeString")) { mimeList.reconstruct(value); registerConverters(); } else if (!wf_strcasecmp(variable, "deleted")) { deleted = atoi(value); } else if (!wf_strcasecmp(variable, "catalog")) { catalog.reconstruct(fc); } else if (!strncmp(variable, "}", 1)) { over = 1; continue; } } // sanity check the fpp if (dlm.filename() == NULL || dlm.status() <= 0 || fpType != WF_FP_DYNAMIC) deleted = 1; return (0); } jdouble * FontDisplayerPeerObject::EnumerateSizes(struct nfrc *rc, void *fh) { // Check for generic preconditions if (deleted || disabled) { return NULL; } // Check for call specific preconditions if (load() < 0) { deleted = 1; return (NULL); } return((jdouble *)nffp_EnumerateSizes(fontDisplayer, rc, fh, NULL)); } struct nffmi * FontDisplayerPeerObject::GetMatchInfo(void *fh) { // Check for generic preconditions if (deleted || disabled) { return (NULL); } // Check for call specific preconditions if (load() < 0) { deleted = 1; return (NULL); } return(nffp_GetMatchInfo(fontDisplayer, fh, NULL)); } struct nfrf * FontDisplayerPeerObject:: CreateRenderableFont(struct nfrc *rc, void *fh, jdouble pointsize) { // Check for generic preconditions if (deleted || disabled) { return (NULL); } // Check for call specific preconditions if (load() < 0) { deleted = 1; return (NULL); } return(nffp_GetRenderableFont(fontDisplayer, rc, fh, pointsize, NULL)); } void * FontDisplayerPeerObject::LookupFont(struct nfrc *rc, struct nffmi *fmi, const char *accessor) { // Check for generic preconditions if (deleted || disabled) { return (NULL); } // Check for call specific preconditions if (load() < 0) { deleted = 1; return (NULL); } return(nffp_LookupFont(fontDisplayer, rc, fmi, accessor, NULL)); } void * FontDisplayerPeerObject::CreateFontFromFile(struct nfrc *rc, const char *mimetype, const char *filename, const char *urlOfPage) { // Check for generic preconditions if (deleted || disabled) { return (NULL); } // Check for call specific preconditions if (load() < 0) { deleted = 1; return (NULL); } return(nffp_CreateFontFromFile(fontDisplayer, rc, mimetype, filename, urlOfPage, NULL)); } struct nfstrm * FontDisplayerPeerObject::CreateFontStreamHandler(struct nfrc *rc, const char *urlOfPage) { // Check for generic preconditions if (deleted || disabled) { return (NULL); } // Check for call specific preconditions if (load() < 0) { deleted = 1; return (NULL); } return((struct nfstrm *) nffp_CreateFontStreamHandler(fontDisplayer, rc, urlOfPage, NULL)); } jint FontDisplayerPeerObject::ReleaseFontHandle(void *fh) { // Check for generic preconditions if (deleted || disabled) { return (-1); } // Check for call specific preconditions if (load() < 0) { deleted = 1; return (-1); } return(nffp_ReleaseFontHandle(fontDisplayer, fh, NULL)); } // // Catalogue routines // struct nffmi ** FontDisplayerPeerObject::ListFonts(struct nfrc *rc, struct nffmi *fmi) { // Check for generic preconditions if (deleted || disabled) { return (NULL); } // Check for call specific preconditions if (load() < 0) { deleted = 1; return (NULL); } return((struct nffmi **) nffp_ListFonts(fontDisplayer, rc, fmi, NULL)); } jdouble * FontDisplayerPeerObject::ListSizes(struct nfrc *rc, struct nffmi *fmi) { // Check for generic preconditions if (deleted || disabled) { return (NULL); } // Check for call specific preconditions if (load() < 0) { deleted = 1; return (NULL); } return((jdouble *) nffp_ListSizes(fontDisplayer, rc, fmi, NULL)); } int FontDisplayerPeerObject::queryCatalog(struct nfrc *rc, struct nffmi *fmi) { int ret = catalog.supportsFmi(rc, fmi); if (ret < 0) { // Catalog may not have been initialized. if (!catalog.isInitialized(rc)) { // Now we need to load the dll to initialize the catalog. struct nffmi **fmis = ListFonts(rc, NULL); catalog.update(rc, fmis); if (fmis) { // XXX We need to free the fmis. We may get away // XXX doing that if we make catalog.update() not // XXX take a copy of the fmi. wf_releaseFmis(fmis); WF_FREE(fmis); } ret = catalog.supportsFmi(rc, fmi); } } return (ret); } // // Displayer loading/unloading management routines // int FontDisplayerPeerObject::dlmChanged(const char *dlm_name) { int ret = -1; // if this is the dlm that we are associcated with if (!strcmp(dlm.filename(), dlm_name)) { if (dlm.isChanged() == 0) { // Unchanged ret = 0; } else { // This mean the dlm has either changed or may have been deleted. ret = 1; } } return (ret); } void FontDisplayerPeerObject::resync(void) { native = -1; finalizeExceptDlmAndDisabled(); // This might cause a core dump as usually a resync() is done only // when we know that the dlm has changed. And if it was loaded in // memory and the disk copy was changed whew! // Some platforms wont let the copy on disk to change. So we are kind of // safe. // // XXX A better solution would be to not unload it at all but just clear our // internal state. Let us see. dlm.unload(/*force*/ 1); dlm.sync(); if (dlm.status() < 0) { deleted = 1; return; } if (load() < 0) { deleted = 1; return; } displayerName = CopyString(nffp_Name(fontDisplayer, NULL)); displayerDescription = CopyString(nffp_Description(fontDisplayer,NULL)); #if defined(XP_WIN) && !defined(WIN32) // Win16 It seems the const char * assignment doesn't work. char mimeString[256]; *mimeString = '\0'; strcpy(mimeString, nffp_EnumerateMimeTypes(fontDisplayer, NULL)); #else const char *mimeString = nffp_EnumerateMimeTypes(fontDisplayer, NULL); #endif if (mimeString && *mimeString ) { mimeList.reconstruct(mimeString); registerConverters(); } } // // mime handling routines // int FontDisplayerPeerObject::countMimetypes() { // Check for generic preconditions if (deleted || disabled) { return (-1); } return (mimeList.count()); } int FontDisplayerPeerObject::isMimetypeEnabled(const char *mimetype) { // Check for generic preconditions if (deleted || disabled) { return (0); } return (mimeList.isEnabled(mimetype)); } const char * FontDisplayerPeerObject::getMimetypeFromExtension(const char *ext) { // Check for generic preconditions if (deleted || disabled) { return (0); } return (mimeList.getMimetypeFromExtension(ext)); } int FontDisplayerPeerObject::disableMimetype(const char *mimetype) { // Check for generic preconditions if (deleted) { return (-1); } return (mimeList.setEnabledStatus(mimetype, 0)); } int FontDisplayerPeerObject::enableMimetype(const char *mimetype) { // Check for generic preconditions if (deleted) { return (-1); } return (mimeList.setEnabledStatus(mimetype, 1)); } // // Additional routines // const char * FontDisplayerPeerObject::name(void) { // Check for generic preconditions if (deleted || disabled) { return (NULL); } return (displayerName); } int FontDisplayerPeerObject::isNative(void) { if (native < 0) { native = 0; // not native if (displayerName) { native = (strcmp(displayerName, NF_NATIVE_FONT_DISPLAYER) == 0); } } // Check if this is the native font displayer return (native); } int FontDisplayerPeerObject::isDeleted(void) { return (deleted); } int FontDisplayerPeerObject::isLoaded(void) { int ret = 0; // Check for generic preconditions if (deleted || disabled) { return (ret); } if (fontDisplayer || fpType == FontDisplayerPeerObject::WF_FP_STATIC) { ret = 1; } return (ret); } void FontDisplayerPeerObject::StreamCreated(struct nfstrm *strm) { streamCount++; } void FontDisplayerPeerObject::StreamDone(struct nfstrm *strm) { streamCount--; decideToUnload(); } void FontDisplayerPeerObject::FontHandleCreated(void *fh) { fhList.add(fh); } void FontDisplayerPeerObject::FontHandleDone(void *fh) { if (fhList.remove(fh) == wfList::SUCCESS) { // If there was no other copy of the fh in our fhlist // then this was the last fh and can be released. if (fhList.isExist(fh) != wfList::SUCCESS) { ReleaseFontHandle(fh); if (fpType == FontDisplayerPeerObject::WF_FP_DYNAMIC) { // Static displayers need not be unloaded. decideToUnload(); } } } } int FontDisplayerPeerObject::disableDisplayer(void) { if (deleted) { return (-1); } disabled = 1; return (0); } int FontDisplayerPeerObject::enableDisplayer(void) { if (deleted) { return (-1); } disabled = 0; return (0); } int FontDisplayerPeerObject::isDisplayerEnabled(void) { if (deleted) { return (0); } return ((disabled ? 0 : 1)); } int FontDisplayerPeerObject::registerConverters(void) { if (deleted) { return (-1); } if (!mimeList.isEmpty()) { // Foreach mime struct wfListElement *tmp = mimeList.head; for (; tmp; tmp = tmp->next) { struct mime_store *ele = (struct mime_store *) tmp->item; NET_cdataCommit(ele->mimetype, ele->extensions); } } return (0); } char * FontDisplayerPeerObject::aboutData(void) { char *aboutData = NULL; int aboutDataLen = 0; int aboutDataMaxLen = 0; #ifndef NO_HTML_DIALOGS_CHANGE #define WF_ABOUT_DATA_ALLOCATION_STEP 64 #define WF_ACCUMULATE(str) wf_addToString(&aboutData, &aboutDataLen, &aboutDataMaxLen, str); // Dont show deleted font displayers. if (isDeleted()) { return (NULL); } // Displayer data char *fmtstring = NULL; char *buf; if (fpType == FontDisplayerPeerObject::WF_FP_STATIC) { fmtstring = XP_GetString(WF_MSG_ABOUT_DISPLAYER_STATIC); buf = PR_smprintf(fmtstring, (displayerName ? displayerName : ""), (displayerDescription ? displayerDescription : "")); } else { fmtstring = XP_GetString(WF_MSG_ABOUT_DISPLAYER_DYNAMIC); buf = PR_smprintf(fmtstring, (displayerName ? displayerName : ""), (displayerDescription ? displayerDescription : ""), dlm.filename()); } if (buf) { WF_ACCUMULATE(buf); XP_FREE(buf); buf = NULL; } if (!mimeList.isEmpty()) { // Foreach mime struct wfListElement *tmp = mimeList.head; for (; tmp; tmp = tmp->next) { struct mime_store *ele = (struct mime_store *) tmp->item; buf = PR_smprintf(XP_GetString(WF_MSG_ABOUT_DISPLAYER_MIME), ele->mimetype, (displayerName ? displayerName : ""), (ele->isEnabled ? "checked" : ""), /* NO I18N */ ele->mimetype, ele->description, ele->extensions); if (buf) { WF_ACCUMULATE(buf); XP_FREE(buf); buf = NULL; } } } WF_ACCUMULATE(XP_GetString(WF_MSG_ABOUT_DISPLAYER_END)); #endif /* NO_HTML_DIALOGS_CHANGE */ return (aboutData); } // // Private method implementations // int FontDisplayerPeerObject::load(void) { // Check for generic preconditions if (deleted || disabled) { return (0); } if (fontDisplayer || fpType == FontDisplayerPeerObject::WF_FP_STATIC) { return (0); } dlm.load(); if (dlm.status() < 0) { return (-1); } fontDisplayer = dlm.createDisplayerObject(WF_fbp); if (!fontDisplayer) { WF_TRACEMSG(("NF: dlm (%s) Couldn't create fontdisplayer object. Skipping dlm.", dlm.filename())); dlm.unload(); return (-1); } return (0); } extern "C" void wf_unloadTimer(void *closure) { FontDisplayerPeerObject *fpp = (FontDisplayerPeerObject *)closure; if (fpp->unloadTimerId) { // One last sanity check if (fpp->streamCount == 0 && fpp->fhList.isEmpty()) { fpp->unload(); } fpp->unloadTimerId = 0; } } void FontDisplayerPeerObject::decideToUnload(void) { if (streamCount == 0 && fhList.isEmpty()) { // This displayer can be unloaded. // I really want to do something like unloading the displayer // after say 1 min. because say the navigator moves from one page // to another and both had use for this displayer, then this displayer // will get loaded twice and unloaded once causing thrashing. // // The problem in implementing this is how to we ensure we get // back control after this many seconds. We should use the // FE Timer callback. // Clear any previous timers if (unloadTimerId) { FE_ClearTimeout(unloadTimerId); } // Set the new timer unloadTimerId = FE_SetTimeout(wf_unloadTimer, this, WF_ONE_MINUTE); } else { // Unload should not happen if (unloadTimerId) { FE_ClearTimeout(unloadTimerId); } } } int FontDisplayerPeerObject::unload(void) { if (fpType == FontDisplayerPeerObject::WF_FP_STATIC) { // Static displayer need not be unloaded. return (0); } if (!fontDisplayer) { // We were never loaded. return (-1); } nffp_release(fontDisplayer, NULL); fontDisplayer = NULL; return (dlm.unload()); } int FontDisplayerPeerObject:: finalizeExceptDlmAndDisabled() { // Release memory if (displayerName) { delete displayerName; displayerName = NULL; } if (displayerDescription) { delete displayerDescription; displayerDescription = NULL; } // Clear native flag native = -1; // Clear deleted flag deleted = 0; // Clean mimelist mimeList.finalize(); // Clean catalog catalog.finalize(); return (0); } int FontDisplayerPeerObject:: finalize() { finalizeExceptDlmAndDisabled(); // Clean dlm unload(); dlm.finalize(); // Clear disabled flag disabled = 0; return (0); }