123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554 |
- #include <precomp.h>
- #include <setjmp.h>
- #include <bfc/bfc_assert.h>
- #include <api.h>
- #include <bfc/wasabi_std.h>
- #include <tataki/bitmap/bitmap.h>
- #include <api/skin/skinfilter.h> // ApplySkinFilters
- #include "imgldr.h"
- #ifdef _WIN32
- #include <api/imgldr/winbmp.h>
- #endif
- #include <api/imgldr/skinbmps.h>
- #include <api/skin/skinparse.h>
- #include <api/skin/skinelem.h>
- #include <api/skin/gammamgr.h>
- #include <api/service/svcs/svc_skinfilter.h>
- #include <api/service/svcs/svc_imgload.h>
- #include <api/service/svcs/svc_imggen.h>
- #include "ImgLoaderEnum.h"
- #include <api/memmgr/api_memmgr.h>
- #include <bfc/string/PathString.h>
- #include <api/locales/localesmgr.h>
- //#define DEBUG_OUTPUT
- #define IMAGEHEADERLEN 256
- #ifdef _WIN32
- ARGB32 *imageLoader::makeBmp(OSMODULEHANDLE hInst, int id, int *has_alpha, int *w, int *h, const wchar_t *forcegroup)
- {
- ARGB32 *bits = makeBmp(StringPrintfW(L"res://%u,%i", hInst, id), NULL, has_alpha, w, h, NULL, TRUE, NULL);
- if (bits && *w > 0 && *h > 0)
- {
- ApplySkinFilters::apply(StringPrintfW(L"resource:%x,%d", hInst, id), forcegroup, bits, *w, *h);
- }
- return bits;
- }
- #endif
- StringW imageLoader::getWallpaper()
- {
- StringW ret(L"");
- #ifdef WIN32
- HKEY hkey;
- static wchar_t file[MAX_PATH];
- file[0] = 0;
- if (RegOpenKey(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), &hkey) == ERROR_SUCCESS)
- {
- unsigned long len = MAX_PATH;
- RegQueryValueExW(hkey, L"Wallpaper", 0, NULL, (unsigned char *)&file, &len);
- RegCloseKey(hkey);
- }
- if (file[0] && GetFileAttributesW(file) != (DWORD) - 1) ret = file;
- #endif
- return ret;
- }
- extern StringW g_resourcepath;
- ARGB32 *imageLoader::makeBmp(const wchar_t *_filename, const wchar_t *path, int *has_alpha, int *w, int *h, ifc_xmlreaderparams *params, bool addMem, int *force_nocache)
- {
- if (!_filename || !*_filename)
- return 0;
-
- ARGB32 *ret = NULL;
- if (has_alpha != NULL)
- *has_alpha = 0; //BU
- // test image generator services FIRST
- ImgGeneratorEnum ige(_filename);
- svc_imageGenerator *gen;
- while ((gen = ige.getNext()) != NULL)
- {
- ret = gen->genImage(_filename, has_alpha, w, h, params);
- int cacheable = gen->outputCacheable();
- ige.release(gen);
- if (ret != NULL)
- {
- ApplySkinFilters::apply(params->getItemValue(L"id"), params->getItemValue(L"gammagroup"), ret, *w, *h);
- if (addMem) addMemUsage(_filename, (*w) * (*h) * sizeof(int));
- optimizeHasAlpha(ret, *w * *h, has_alpha);
- // don't try to cache generated images
- if (force_nocache) *force_nocache = !cacheable;
- return ret;
- }
- }
- StringW wallpaper;
- if (!WCSICMP(_filename, L"$wallpaper"))
- {
- wallpaper = getWallpaper();
- _filename = wallpaper.getValue();
- }
- MemBlock<uint8_t> mem;
- wchar_t olddir[PATH_MAX] = {0};
- Wasabi::Std::getCurDir(olddir, PATH_MAX);
- Wasabi::Std::setCurDir(WASABI_API_APP->path_getAppPath());
- StringW file;
- // benski> try language pack first
- StringPathCombine skinLocalePath(LocalesManager::getLocaleRoot(), WASABI_API_SKIN->getSkinName());
- file.swap(StringPathCombine(skinLocalePath, _filename));
- OSFILETYPE in = WFOPEN(file, WF_READONLY_BINARY);
- if (in == OPEN_FAILED)
- {
- // try the language pack's folder itself before falling back to the resource path
- file.swap(StringPathCombine(LocalesManager::getLocaleRoot(), _filename));
- in = WFOPEN(file, WF_READONLY_BINARY);
- }
- if (in == OPEN_FAILED)
- {
- if (path)
- {
- file.swap(StringPathCombine(path, _filename));
- in = WFOPEN(file, WF_READONLY_BINARY);
- }
- else
- in = WFOPEN(file=_filename, WF_READONLY_BINARY);
- }
- #ifdef WASABI_COMPILE_SKIN
- if (in == OPEN_FAILED)
- {
- file.swap(StringPathCombine(WASABI_API_SKIN->getSkinPath(), _filename));
- in = WFOPEN(file, WF_READONLY_BINARY);
- }
- #if 0 // this isn't used in gen_ff, basically makes it look in C:/Program Files/Winamp/Skins/Default/
- if (in == OPEN_FAILED)
- {
- file.swap(StringPathCombine(Skin::getDefaultSkinPath(), _filename));
- in = WFOPEN(file, WF_READONLY_BINARY);
- }
- #endif
- // look in the fallback stuff (in Winamp5, this is c:/program files/winamp/plugins/freeform/xml)
- if (in == OPEN_FAILED)
- {
- file.swap(StringPathCombine(g_resourcepath, _filename));
- in = WFOPEN(file, WF_READONLY_BINARY);
- }
- #endif
- if (in == OPEN_FAILED && path)
- {
- in = WFOPEN(file = _filename, WF_READONLY_BINARY);
- }
- Wasabi::Std::setCurDir(olddir);
- if (in != OPEN_FAILED)
- {
- int filelen = (int)FGETSIZE(in);
- if (filelen > 0)
- {
- mem.setSize(filelen);
- int len = FREAD(mem, 1, mem.getSizeInBytes(), in);
- if (len == filelen)
- {
- svc_imageLoader *loader = ImgLoaderEnum(mem, len).getNext();
- if (loader != NULL)
- {
- ret = loader->loadImage(mem, mem.getSizeInBytes(), w, h, params);
- if (ret != NULL)
- {
- if (addMem)
- addMemUsage(file, (*w) * (*h) * sizeof(ARGB32));
- optimizeHasAlpha(ret, *w * *h, has_alpha);
- }
- SvcEnum::release(loader);
- }
- }
- } // filelen > 0
- FCLOSE(in);
- } // if file opened
- if (ret != NULL)
- {
- return ret;
- }
- else if (in != OPEN_FAILED && mem)
- {
- int m = getFileType(mem);
- #ifdef WIN32
- switch (m)
- {
- case FT_BMP:
- {
- wchar_t tmpname[WA_MAX_PATH] = L"";
- // FG> if loading bmp from disk, no need to do the copy to disk
- HBITMAP hbmp = (HBITMAP)LoadImageW(0, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
- if (!hbmp)
- {
- // CT> extract/copy the file into temp directory (so we don't have any trouble if the file
- // is in a ZIP file). this whole copying thing will go away as soon as we'll get rid of
- // the LoadImage win32 function and use our own bmp loading functions
- GetTempPathW(WA_MAX_PATH, tmpname);
- wcscat(tmpname, L"wa3tmp");
- OSFILETYPE fs = WFOPEN(file, WF_READONLY_BINARY);
- if (fs != OPEN_FAILED)
- {
- OSFILETYPE fd = WFOPEN(tmpname, L"wb");
- int l;
- do
- {
- char buf[1024] = {0};
- l = FREAD(buf, 1, sizeof(buf), fs);
- if (l > 0) FWRITE(buf, 1, l, fd);
- }
- while (l > 0);
- FCLOSE(fs);
- FCLOSE(fd);
- hbmp = (HBITMAP)LoadImageW(0, tmpname, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
- }
- if (!hbmp)
- {
- #ifdef WASABI_COMPILE_SKIN_WA2
- // bitmap not found or broken (like in the netscape skin)
- // try to find it in the Classic skin (wa2)
- StringW wa2skinFn = WASABI_API_APP->getSkinsPath();
- wa2skinFn.AppendPath("Classic");
- wa2skinFn.AppendPath(_filename);
- fs = WFOPEN(wa2skinFn), WF_READONLY_BINARY);
- if (fs != OPEN_FAILED)
- {
- OSFILETYPE fd = WFOPEN(tmpname, L"wb");
- int l;
- do
- {
- char buf[1024] = {0};
- l = FREAD(buf, 1, sizeof(buf), fs);
- if (l > 0) FWRITE(buf, 1, l, fd);
- }
- while (l > 0);
- FCLOSE(fs);
- FCLOSE(fd);
- hbmp = (HBITMAP)LoadImageW(0, tmpname, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
- }
- #endif //WASABI_COMPILE_SKIN_WA2
- }
- if (!hbmp)
- {
- // no luck :(
- _wunlink(tmpname);
- return 0;
- }
- }
- BITMAP bm;
- HDC hMemDC, hMemDC2;
- HBITMAP hprev, hprev2;
- HBITMAP hsrcdib;
- void *srcdib;
- BITMAPINFO srcbmi = {0, };
- int r = GetObject(hbmp, sizeof(BITMAP), &bm);
- ASSERT(r != 0);
- *w = bm.bmWidth;
- *h = ABS(bm.bmHeight);
- ARGB32 *newbits;
- srcbmi.bmiHeader.biSize = sizeof(srcbmi.bmiHeader);
- srcbmi.bmiHeader.biWidth = *w;
- srcbmi.bmiHeader.biHeight = -*h;
- srcbmi.bmiHeader.biPlanes = 1;
- srcbmi.bmiHeader.biBitCount = 32;
- srcbmi.bmiHeader.biCompression = BI_RGB;
- hMemDC = CreateCompatibleDC(NULL);
- hMemDC2 = CreateCompatibleDC(NULL);
- hsrcdib = CreateDIBSection(hMemDC, &srcbmi, DIB_RGB_COLORS, &srcdib, NULL, 0);
- ASSERTPR(hsrcdib != 0, "CreateDIBSection() failed #69");
- hprev2 = (HBITMAP) SelectObject(hMemDC2, hbmp);
- hprev = (HBITMAP) SelectObject(hMemDC, hsrcdib);
- BitBlt(hMemDC, 0, 0, *w, *h, hMemDC2, 0, 0, SRCCOPY);
- newbits = (ARGB32*)MALLOC((*w) * (*h) * sizeof(ARGB32));
- MEMCPY32(newbits, srcdib, (*w)*(*h) /**sizeof(ARGB32)*/);
- {
- // put the alpha channel to 255
- unsigned char *b = (unsigned char *)newbits;
- int l = (*w) * (*h);
- for (int i = 0;i < l;i++)
- b[(i*4) + 3] = 0xff;
- }
- SelectObject(hMemDC, hprev);
- SelectObject(hMemDC2, hprev2);
- DeleteObject(hsrcdib);
- DeleteDC(hMemDC2);
- DeleteDC(hMemDC);
- DeleteObject(hbmp);
- if (tmpname[0])
- _wunlink(tmpname); // destroy temp extraction
- if (addMem)
- addMemUsage(file, (*w)*(*h)*4);
- return newbits;
- }
- }
- #endif
- }
- return ret;
- }
- int imageLoader::getFileType(unsigned char *pData)
- {
- // Bmp ?
- #ifdef WIN32
- WINBITMAPFILEHEADER * pBFH;
- pBFH = (WINBITMAPFILEHEADER *) pData;
- #ifdef _WINDOWS
- if (pBFH->bfType == 0x4d42)
- #else
- if (pBFH->bfType == 0x424d)
- #endif
- return FT_BMP;
- #endif
- return FT_UNKNOWN;
- }
- #ifdef WASABI_COMPILE_SKIN
- ARGB32 *imageLoader::requestSkinBitmap(const wchar_t *id, int *has_alpha, int *x, int *y, int *subw, int *subh, int *w, int *h, int cached)
- {
- ifc_xmlreaderparams *params = NULL;
- const wchar_t *rootpath = NULL;
- const wchar_t *aliastarget = WASABI_API_PALETTE->getElementAlias(id);
- if (aliastarget)
- id = aliastarget;
- const wchar_t *efile = WASABI_API_PALETTE->getSkinBitmapFilename(id, x, y, subw, subh, &rootpath, ¶ms);
- if (x && *x == -1) *x = 0;
- if (y && *y == -1) *y = 0;
-
- if (!efile)
- efile = id;
- if (cached)
- {
- StringPathCombine f(rootpath, efile);
- f.toupper();
- f.FixSlashes();
- int pos = -1;
- /*skinCacheEntry *entry = */skinCacheList.findItem(f.getValue(), &pos);
- if (pos != -1)
- {
- //find first one
- while (pos > 0 && !wcscmp(skinCacheList[pos - 1]->fullpathfilename, f)) pos--;
- do
- {
- skinCacheEntry *entry = skinCacheList[pos];
- if (GammaMgr::gammaEqual(entry->original_element_id, id) && layerEqual(entry->original_element_id, id))
- {
- entry->usageCount++;
- if (w) *w = entry->width;
- if (h) *h = entry->height;
- if (has_alpha) *has_alpha = entry->has_alpha;
- return entry->bitmapbits;
- }
- pos++;
- if (pos >= skinCacheList.getNumItems()) break;
- }
- while (!wcscmp(skinCacheList[pos]->fullpathfilename, f));
- }
- }
- int force_nocache = 0;
- int t_has_alpha = 0;
- ARGB32 *bits = makeBmp(efile, rootpath, &t_has_alpha, w, h, params, TRUE, &force_nocache);
- if (has_alpha != NULL) *has_alpha = t_has_alpha;
- if (!bits)
- return NULL;
- if (force_nocache || !cached) return bits;
- skinCacheEntry *cachedbmp = new skinCacheEntry;
- if (params)
- {
- for (size_t i = 0;i != params->getNbItems();i++)
- cachedbmp->params.addItem(params->getItemName(i), params->getItemValue(i));
- }
- cachedbmp->usageCount = 1;
- cachedbmp->bitmapbits = bits;
- cachedbmp->filename = efile;
- cachedbmp->has_alpha = !!t_has_alpha;
- cachedbmp->width = *w;
- cachedbmp->height = *h;
- cachedbmp->original_element_id = id;
- //needed for findItem above
- StringPathCombine b(rootpath, efile);
- b.toupper();
- b.FixSlashes();
- cachedbmp->fullpathfilename.swap(b);
- applySkinFilters(cachedbmp);
- skinCacheList.addItem(cachedbmp);
- return cachedbmp->bitmapbits;
- }
- /*
- int imageLoader::paramsMatch(ifc_xmlreaderparams *a, ifc_xmlreaderparams *b)
- {
- if (!a && !b) return 1;
- if ((!a && b) || (!b && a)) return 0;
- for (int i = 0;i < a->getNbItems();i++)
- {
- const wchar_t *name = a->getItemName(i);
- if (!_wcsicmp(name, L"w") || !_wcsicmp(name, L"h") || !_wcsicmp(name, L"x") || !_wcsicmp(name, L"y")) continue;
- if (_wcsicmp(a->getItemValue(i), b->getItemValue(name)))
- return 0;
- }
- return 1;
- }
- */
- int imageLoader::layerEqual(const wchar_t *id1, const wchar_t *id2)
- {
- int a = WASABI_API_PALETTE->getLayerFromId(id1);
- int b = WASABI_API_PALETTE->getLayerFromId(id2);
- return (a == b);
- }
- void imageLoader::releaseSkinBitmap(ARGB32 *bitmapbits)
- { //FG
- int i;
- // TODO: add critical sections
- int ni = skinCacheList.getNumItems();
- for (i = 0;i < ni;i++)
- {
- skinCacheEntry *entry = skinCacheList.enumItem(i);
- if (entry->bitmapbits == bitmapbits)
- {
- entry->usageCount--;
- if (entry->usageCount == 0)
- {
- subMemUsage(entry->width*entry->height*sizeof(int));
- WASABI_API_MEMMGR->sysFree(entry->bitmapbits);
- skinCacheList.removeByPos(i);
- delete entry;
- if (skinCacheList.getNumItems() == 0) skinCacheList.removeAll();
- }
- return ;
- }
- }
- // bitmap was not a cached skin bitmap, simply free it
- release(bitmapbits);
- }
- #endif //WASABI_COMPILE_SKIN
- void imageLoader::release(ARGB32 *bitmapbits)
- {
- WASABI_API_MEMMGR->sysFree(bitmapbits);
- }
- void imageLoader::optimizeHasAlpha(ARGB32 *bits, int len, int *has_alpha)
- {
- if (len <= 0 || has_alpha == NULL) return ;
- for (*has_alpha = 0; len; len--, bits++)
- {
- ARGB32 v = *bits;
- unsigned int alpha = v >> 24;
- if (alpha != 255)
- {
- *has_alpha = 1;
- break;
- }
- }
- }
- #ifdef WASABI_COMPILE_SKIN
- void imageLoader::applySkinFilters()
- { //FG
- int i;
- Skin::unloadResources();
- for (i = 0; i < skinCacheList.getNumItems(); i++)
- {
- skinCacheEntry *entry = skinCacheList.q(i);
- applySkinFilters(entry);
- }
- WASABI_API_PALETTE->newSkinPart();
- Skin::reloadResources();
- }
- void imageLoader::applySkinFilters(skinCacheEntry *entry)
- {
- ASSERT(entry != NULL);
- int w = entry->width, h = entry->height;
- ApplySkinFilters::apply(entry->original_element_id, NULL, (ARGB32*)entry->bitmapbits, w, h);
- }
- ARGB32 imageLoader::filterSkinColor(ARGB32 color, const wchar_t *element_id, const wchar_t *groupname)
- {
- SkinFilterEnum sfe;
- svc_skinFilter *obj;
- while (1)
- {
- obj = sfe.getNext(FALSE);
- if (!obj) break;
- color = obj->filterColor(color, element_id, groupname);
- sfe.getLastFactory()->releaseInterface(obj);
- }
- return color;
- }
- #endif //WASABI_COMPILE_SKIN
- void imageLoader::addMemUsage(const wchar_t *filename, int size)
- {
- totalMemUsage += size;
- #ifdef DEBUG_OUTPUT
- DebugStringW("Bitmaps memory usage : %s - %d\n", filename, totalMemUsage);
- #endif
- }
- void imageLoader::subMemUsage(int size)
- {
- totalMemUsage -= size;
- }
- #ifdef WASABI_COMPILE_SKIN
- //PtrList<skinCacheEntry> imageLoader::skinCacheList;
- PtrListInsertMultiSorted<skinCacheEntry, skinCacheComp> imageLoader::skinCacheList;
- #endif //WASABI_COMPILE_SKIN
- int imageLoader::totalMemUsage = 0;
|