PageRenderTime 822ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/kits/tracker/IconCache.cpp

http://github.com/Barrett17/Haiku-services-branch
C++ | 1999 lines | 1413 code | 396 blank | 190 comment | 273 complexity | cc10f79ce12be6c9d95055af958fb9e4 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0, LGPL-2.0, LGPL-2.1, BSD-2-Clause, ISC, Apache-2.0, AGPL-1.0, MIT, MPL-2.0-no-copyleft-exception, Unlicense, BSD-3-Clause, LGPL-3.0
  1. /*
  2. Open Tracker License
  3. Terms and Conditions
  4. Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
  5. Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. this software and associated documentation files (the "Software"), to deal in
  7. the Software without restriction, including without limitation the rights to
  8. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  9. of the Software, and to permit persons to whom the Software is furnished to do
  10. so, subject to the following conditions:
  11. The above copyright notice and this permission notice applies to all licensees
  12. and shall be included in all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
  15. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  16. BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  17. AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
  18. WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. Except as contained in this notice, the name of Be Incorporated shall not be
  20. used in advertising or otherwise to promote the sale, use or other dealings in
  21. this Software without prior written authorization from Be Incorporated.
  22. Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
  23. of Be Incorporated in the United States and other countries. Other brand product
  24. names are registered trademarks or trademarks of their respective holders.
  25. All rights reserved.
  26. */
  27. // Icon cache is used for drawing node icons; it caches icons
  28. // and reuses them for successive draws
  29. //
  30. // Possible performance improvements:
  31. // - Mime API requires BBitmaps to retrieve bits and successive
  32. // SetBits that cause app server contention
  33. // Consider having special purpose "give me just the bits" calls
  34. // to deal with that.
  35. // - Related to this, node cache entries would only store the raw bits
  36. // to cut down on number of BBitmaps and related overhead
  37. // - Make the cache miss and fill case for the shared cache reuse the
  38. // already calculated hash value
  39. //
  40. // Other ToDo items:
  41. // Use lazily allocated bitmap arrays for every view for node icon cache
  42. // drawing
  43. // Have an overflow list for deleting shared icons, delete from the list
  44. // every now and then
  45. // Actual icon lookup sequence:
  46. // icon from node
  47. // preferred app for node -> icon for type
  48. // preferred app for type -> icon for type
  49. // metamime -> icon for type
  50. // preferred app for supertype -> icon for type
  51. // supertype metamime -> icon for type
  52. // generic icon
  53. #include <Debug.h>
  54. #include <Screen.h>
  55. #include <Volume.h>
  56. #include <fs_info.h>
  57. #include "Bitmaps.h"
  58. #include "FSUtils.h"
  59. #include "IconCache.h"
  60. #include "MimeTypes.h"
  61. #include "Model.h"
  62. #if DEBUG
  63. // #define LOG_DISK_HITS
  64. // the LOG_DISK_HITS define is used to check that the disk is not hit more
  65. // than needed - enable it, open a window with a bunch of poses, force
  66. // it to redraw, shouldn't recache
  67. // #define LOG_ADD_ITEM
  68. #endif
  69. // set up a few printing macros to get rid of a ton of debugging ifdefs in the code
  70. #ifdef LOG_DISK_HITS
  71. #define PRINT_DISK_HITS(ARGS) _debugPrintf ARGS
  72. #else
  73. #define PRINT_DISK_HITS(ARGS) (void)0
  74. #endif
  75. #ifdef LOG_ADD_ITEM
  76. #define PRINT_ADD_ITEM(ARGS) _debugPrintf ARGS
  77. #else
  78. #define PRINT_ADD_ITEM(ARGS) (void)0
  79. #endif
  80. #undef NODE_CACHE_ASYNC_DRAWS
  81. IconCacheEntry::IconCacheEntry()
  82. : fLargeIcon(NULL),
  83. fMiniIcon(NULL),
  84. fHilitedLargeIcon(NULL),
  85. fHilitedMiniIcon(NULL),
  86. fAliasForIndex(-1)
  87. {
  88. }
  89. IconCacheEntry::~IconCacheEntry()
  90. {
  91. if (fAliasForIndex < 0) {
  92. delete fLargeIcon;
  93. delete fMiniIcon;
  94. delete fHilitedLargeIcon;
  95. delete fHilitedMiniIcon;
  96. // clean up a bit to leave the hash table entry in an initialized state
  97. fLargeIcon = NULL;
  98. fMiniIcon = NULL;
  99. fHilitedLargeIcon = NULL;
  100. fHilitedMiniIcon = NULL;
  101. }
  102. fAliasForIndex = -1;
  103. }
  104. void
  105. IconCacheEntry::SetAliasFor(const SharedIconCache* sharedCache,
  106. const SharedCacheEntry* entry)
  107. {
  108. sharedCache->SetAliasFor(this, entry);
  109. ASSERT(fAliasForIndex >= 0);
  110. }
  111. IconCacheEntry*
  112. IconCacheEntry::ResolveIfAlias(const SharedIconCache* sharedCache)
  113. {
  114. return sharedCache->ResolveIfAlias(this);
  115. }
  116. IconCacheEntry*
  117. IconCacheEntry::ResolveIfAlias(const SharedIconCache* sharedCache,
  118. IconCacheEntry* entry)
  119. {
  120. if (!entry)
  121. return NULL;
  122. return sharedCache->ResolveIfAlias(entry);
  123. }
  124. bool
  125. IconCacheEntry::CanConstructBitmap(IconDrawMode mode, icon_size) const
  126. {
  127. if (mode == kSelected)
  128. // for now only
  129. return true;
  130. return false;
  131. }
  132. bool
  133. IconCacheEntry::HaveIconBitmap(IconDrawMode mode, icon_size size) const
  134. {
  135. ASSERT(mode == kSelected || mode == kNormalIcon);
  136. // for now only
  137. if (mode == kNormalIcon) {
  138. if (size == B_MINI_ICON)
  139. return fMiniIcon != NULL;
  140. else
  141. return fLargeIcon != NULL
  142. && fLargeIcon->Bounds().IntegerWidth() + 1 == size;
  143. } else if (mode == kSelected) {
  144. if (size == B_MINI_ICON)
  145. return fHilitedMiniIcon != NULL;
  146. else
  147. return fHilitedLargeIcon != NULL
  148. && fHilitedLargeIcon->Bounds().IntegerWidth() + 1 == size;
  149. }
  150. return false;
  151. }
  152. BBitmap*
  153. IconCacheEntry::IconForMode(IconDrawMode mode, icon_size size) const
  154. {
  155. ASSERT(mode == kSelected || mode == kNormalIcon);
  156. // for now only
  157. if (mode == kNormalIcon) {
  158. if (size == B_MINI_ICON)
  159. return fMiniIcon;
  160. else
  161. return fLargeIcon;
  162. } else if (mode == kSelected) {
  163. if (size == B_MINI_ICON)
  164. return fHilitedMiniIcon;
  165. else
  166. return fHilitedLargeIcon;
  167. }
  168. return NULL;
  169. }
  170. bool
  171. IconCacheEntry::IconHitTest(BPoint where, IconDrawMode mode, icon_size size) const
  172. {
  173. ASSERT(where.x < size && where.y < size);
  174. BBitmap* bitmap = IconForMode(mode, size);
  175. if (!bitmap)
  176. return false;
  177. uchar* bits = (uchar*)bitmap->Bits();
  178. ASSERT(bits);
  179. BRect bounds(bitmap->Bounds());
  180. bounds.InsetBy((bounds.Width() + 1.0) / 8.0, (bounds.Height() + 1.0) / 8.0);
  181. if (bounds.Contains(where))
  182. return true;
  183. switch (bitmap->ColorSpace()) {
  184. case B_RGBA32:
  185. // test alpha channel
  186. return *(bits + (int32)(floorf(where.y) * bitmap->BytesPerRow()
  187. + floorf(where.x) * 4 + 3)) > 20;
  188. case B_CMAP8:
  189. return *(bits + (int32)(floorf(where.y) * size + where.x))
  190. != B_TRANSPARENT_8_BIT;
  191. default:
  192. return true;
  193. }
  194. }
  195. BBitmap*
  196. IconCacheEntry::ConstructBitmap(BBitmap* constructFrom,
  197. IconDrawMode requestedMode, IconDrawMode constructFromMode,
  198. icon_size size, LazyBitmapAllocator* lazyBitmap)
  199. {
  200. ASSERT(requestedMode == kSelected && constructFromMode == kNormalIcon);
  201. // for now
  202. if (requestedMode == kSelected && constructFromMode == kNormalIcon) {
  203. return IconCache::sIconCache->MakeSelectedIcon(constructFrom, size,
  204. lazyBitmap);
  205. }
  206. return NULL;
  207. }
  208. BBitmap*
  209. IconCacheEntry::ConstructBitmap(IconDrawMode requestedMode, icon_size size,
  210. LazyBitmapAllocator* lazyBitmap)
  211. {
  212. BBitmap* source = (size == B_MINI_ICON) ? fMiniIcon : fLargeIcon;
  213. ASSERT(source);
  214. return ConstructBitmap(source, requestedMode, kNormalIcon, size,
  215. lazyBitmap);
  216. }
  217. bool
  218. IconCacheEntry::AlternateModeForIconConstructing(IconDrawMode requestedMode,
  219. IconDrawMode &alternate, icon_size)
  220. {
  221. if (requestedMode & kSelected) {
  222. // for now
  223. alternate = kNormalIcon;
  224. return true;
  225. }
  226. return false;
  227. }
  228. void
  229. IconCacheEntry::SetIcon(BBitmap* bitmap, IconDrawMode mode, icon_size size,
  230. bool /*create*/)
  231. {
  232. if (mode == kNormalIcon) {
  233. if (size == B_MINI_ICON)
  234. fMiniIcon = bitmap;
  235. else
  236. fLargeIcon = bitmap;
  237. } else if (mode == kSelectedIcon) {
  238. if (size == B_MINI_ICON)
  239. fHilitedMiniIcon = bitmap;
  240. else
  241. fHilitedLargeIcon = bitmap;
  242. } else
  243. TRESPASS();
  244. }
  245. IconCache::IconCache()
  246. : fInitHiliteTable(true)
  247. {
  248. InitHiliteTable();
  249. }
  250. // The following calls use the icon lookup sequence node-prefered app for
  251. // node-metamime-preferred app for metamime to find an icon;
  252. // if we are trying to get a specialized icon, we will first look for a normal
  253. // icon in each of the locations, if we get a hit, we look for the
  254. // specialized, if we don't find one, we try to auto-construct one, if we
  255. // can't we assume the icon is not available for now the code only looks for
  256. // normal icons, selected icons are auto-generated
  257. IconCacheEntry*
  258. IconCache::GetIconForPreferredApp(const char* fileTypeSignature,
  259. const char* preferredApp, IconDrawMode mode, icon_size size,
  260. LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry)
  261. {
  262. ASSERT(fSharedCache.IsLocked());
  263. if (!preferredApp[0])
  264. return NULL;
  265. if (!entry) {
  266. entry = fSharedCache.FindItem(fileTypeSignature, preferredApp);
  267. if (entry) {
  268. entry = entry->ResolveIfAlias(&fSharedCache, entry);
  269. #if xDEBUG
  270. PRINT(("File %s; Line %d # looking for %s, type %s, found %x\n",
  271. __FILE__, __LINE__, preferredApp, fileTypeSignature, entry));
  272. #endif
  273. if (entry->HaveIconBitmap(mode, size))
  274. return entry;
  275. }
  276. }
  277. if (!entry || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  278. PRINT_DISK_HITS(
  279. ("File %s; Line %d # hitting disk for preferredApp %s, type %s\n",
  280. __FILE__, __LINE__, preferredApp, fileTypeSignature));
  281. BMimeType preferredAppType(preferredApp);
  282. BString signature(fileTypeSignature);
  283. signature.ToLower();
  284. if (preferredAppType.GetIconForType(signature.String(),
  285. lazyBitmap->Get(), size) != B_OK) {
  286. return NULL;
  287. }
  288. BBitmap* bitmap = lazyBitmap->Adopt();
  289. if (!entry) {
  290. PRINT_ADD_ITEM(
  291. ("File %s; Line %d # adding entry for preferredApp %s, "
  292. "type %s\n", __FILE__, __LINE__, preferredApp,
  293. fileTypeSignature));
  294. entry = fSharedCache.AddItem(fileTypeSignature, preferredApp);
  295. }
  296. entry->SetIcon(bitmap, kNormalIcon, size);
  297. }
  298. if (mode != kNormalIcon
  299. && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  300. entry->ConstructBitmap(mode, size, lazyBitmap);
  301. entry->SetIcon(lazyBitmap->Adopt(), mode, size);
  302. }
  303. return entry;
  304. }
  305. IconCacheEntry*
  306. IconCache::GetIconFromMetaMime(const char* fileType, IconDrawMode mode,
  307. icon_size size, LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry)
  308. {
  309. ASSERT(fSharedCache.IsLocked());
  310. if (!entry)
  311. entry = fSharedCache.FindItem(fileType);
  312. if (entry) {
  313. entry = entry->ResolveIfAlias(&fSharedCache, entry);
  314. // metamime defines an icon and we have it cached
  315. if (entry->HaveIconBitmap(mode, size))
  316. return entry;
  317. }
  318. if (!entry || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  319. PRINT_DISK_HITS(("File %s; Line %d # hitting disk for metamime %s\n",
  320. __FILE__, __LINE__, fileType));
  321. BMimeType mime(fileType);
  322. // try getting the icon directly from the metamime
  323. if (mime.GetIcon(lazyBitmap->Get(), size) != B_OK) {
  324. // try getting it from the preferred app of this type
  325. char preferredAppSig[B_MIME_TYPE_LENGTH];
  326. if (mime.GetPreferredApp(preferredAppSig) != B_OK)
  327. return NULL;
  328. SharedCacheEntry* aliasTo = NULL;
  329. if (entry) {
  330. aliasTo
  331. = (SharedCacheEntry*)entry->ResolveIfAlias(&fSharedCache);
  332. }
  333. // look for icon defined by preferred app from metamime
  334. aliasTo = (SharedCacheEntry*)GetIconForPreferredApp(fileType,
  335. preferredAppSig, mode, size, lazyBitmap, aliasTo);
  336. if (aliasTo == NULL)
  337. return NULL;
  338. // make an aliased entry so that the next time we get a
  339. // hit on the first FindItem in here
  340. if (!entry) {
  341. PRINT_ADD_ITEM(
  342. ("File %s; Line %d # adding entry as alias for type %s\n",
  343. __FILE__, __LINE__, fileType));
  344. entry = fSharedCache.AddItem(&aliasTo, fileType);
  345. entry->SetAliasFor(&fSharedCache, aliasTo);
  346. }
  347. ASSERT(aliasTo->HaveIconBitmap(mode, size));
  348. return aliasTo;
  349. }
  350. // at this point, we've found an icon for the MIME type
  351. BBitmap* bitmap = lazyBitmap->Adopt();
  352. if (!entry) {
  353. PRINT_ADD_ITEM(("File %s; Line %d # adding entry for type %s\n",
  354. __FILE__, __LINE__, fileType));
  355. entry = fSharedCache.AddItem(fileType);
  356. }
  357. entry->SetIcon(bitmap, kNormalIcon, size);
  358. }
  359. ASSERT(entry);
  360. if (mode != kNormalIcon
  361. && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  362. entry->ConstructBitmap(mode, size, lazyBitmap);
  363. entry->SetIcon(lazyBitmap->Adopt(), mode, size);
  364. }
  365. #if xDEBUG
  366. if (!entry->HaveIconBitmap(mode, size))
  367. PRINT(("failing on %s, mode %ld, size %ld\n", fileType, mode, size));
  368. #endif
  369. ASSERT(entry->HaveIconBitmap(mode, size));
  370. return entry;
  371. }
  372. IconCacheEntry*
  373. IconCache::GetIconFromFileTypes(ModelNodeLazyOpener* modelOpener,
  374. IconSource &source, IconDrawMode mode, icon_size size,
  375. LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry)
  376. {
  377. ASSERT(fSharedCache.IsLocked());
  378. // use file types to get the icon
  379. Model* model = modelOpener->TargetModel();
  380. const char* fileType = model->MimeType();
  381. const char* nodePreferredApp = model->PreferredAppSignature();
  382. if (source == kUnknownSource || source == kUnknownNotFromNode
  383. || source == kPreferredAppForNode) {
  384. if (nodePreferredApp[0]) {
  385. // file has a locally set preferred app, try getting an icon from
  386. // there
  387. entry = GetIconForPreferredApp(fileType, nodePreferredApp, mode,
  388. size, lazyBitmap, entry);
  389. #if xDEBUG
  390. PRINT(("File %s; Line %d # looking for %s, type %s, found %x\n",
  391. __FILE__, __LINE__, nodePreferredApp, fileType, entry));
  392. #endif
  393. if (entry) {
  394. source = kPreferredAppForNode;
  395. ASSERT(entry->HaveIconBitmap(mode, size));
  396. return entry;
  397. }
  398. }
  399. if (source == kPreferredAppForNode)
  400. source = kUnknownSource;
  401. }
  402. entry = GetIconFromMetaMime(fileType, mode, size, lazyBitmap, entry);
  403. if (!entry) {
  404. // Try getting a supertype handler icon
  405. BMimeType mime(fileType);
  406. if (!mime.IsSupertypeOnly()) {
  407. BMimeType superType;
  408. mime.GetSupertype(&superType);
  409. const char* superTypeFileType = superType.Type();
  410. if (superTypeFileType)
  411. entry = GetIconFromMetaMime(superTypeFileType, mode, size,
  412. lazyBitmap, entry);
  413. #if DEBUG
  414. else
  415. PRINT(
  416. ("File %s; Line %d # failed to get supertype for "
  417. "type %s\n", __FILE__, __LINE__, fileType));
  418. #endif
  419. }
  420. }
  421. ASSERT(!entry || entry->HaveIconBitmap(mode, size));
  422. if (entry) {
  423. if (nodePreferredApp[0]) {
  424. // we got a miss using GetIconForPreferredApp before, cache this
  425. // fileType/preferredApp combo with an aliased entry
  426. // make an aliased entry so that the next time we get a
  427. // hit and substitute a generic icon right away
  428. PRINT_ADD_ITEM(
  429. ("File %s; Line %d # adding entry as alias for "
  430. "preferredApp %s, type %s\n",
  431. __FILE__, __LINE__, nodePreferredApp, fileType));
  432. IconCacheEntry* aliasedEntry
  433. = fSharedCache.AddItem((SharedCacheEntry**)&entry, fileType,
  434. nodePreferredApp);
  435. aliasedEntry->SetAliasFor(&fSharedCache,
  436. (SharedCacheEntry*)entry);
  437. // OK to cast here, have a runtime check
  438. source = kPreferredAppForNode;
  439. // set source as preferred for node, so that next time we
  440. // get a hit in the initial find that uses
  441. // GetIconForPreferredApp
  442. } else
  443. source = kMetaMime;
  444. #if DEBUG
  445. if (!entry->HaveIconBitmap(mode, size))
  446. model->PrintToStream();
  447. #endif
  448. ASSERT(entry->HaveIconBitmap(mode, size));
  449. }
  450. return entry;
  451. }
  452. IconCacheEntry*
  453. IconCache::GetVolumeIcon(AutoLock<SimpleIconCache>*nodeCacheLocker,
  454. AutoLock<SimpleIconCache>* sharedCacheLocker,
  455. AutoLock<SimpleIconCache>** resultingOpenCache,
  456. Model* model, IconSource &source,
  457. IconDrawMode mode, icon_size size, LazyBitmapAllocator* lazyBitmap)
  458. {
  459. *resultingOpenCache = nodeCacheLocker;
  460. nodeCacheLocker->Lock();
  461. IconCacheEntry* entry = 0;
  462. if (source != kUnknownSource) {
  463. // cached in the node cache
  464. entry = fNodeCache.FindItem(model->NodeRef());
  465. if (entry) {
  466. entry = IconCacheEntry::ResolveIfAlias(&fSharedCache, entry);
  467. if (source == kTrackerDefault) {
  468. // if tracker default, resolved entry is from shared cache
  469. // this could be done a little cleaner if entry had a way to
  470. // reach the cache it is in
  471. *resultingOpenCache = sharedCacheLocker;
  472. sharedCacheLocker->Lock();
  473. }
  474. if (entry->HaveIconBitmap(mode, size))
  475. return entry;
  476. }
  477. }
  478. // try getting using the BVolume::GetIcon call; if miss,
  479. // go for the default mime based icon
  480. if (!entry || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  481. BVolume volume(model->NodeRef()->device);
  482. if (volume.IsShared()) {
  483. // Check if it's a network share and give it a special icon
  484. BBitmap* bitmap = lazyBitmap->Get();
  485. GetTrackerResources()->GetIconResource(R_ShareIcon, size, bitmap);
  486. if (!entry) {
  487. PRINT_ADD_ITEM(
  488. ("File %s; Line %d # adding entry for model %s\n",
  489. __FILE__, __LINE__, model->Name()));
  490. entry = fNodeCache.AddItem(model->NodeRef());
  491. }
  492. entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size);
  493. } else if (volume.GetIcon(lazyBitmap->Get(), size) == B_OK) {
  494. // Ask the device for an icon
  495. BBitmap* bitmap = lazyBitmap->Adopt();
  496. ASSERT(bitmap);
  497. if (!entry) {
  498. PRINT_ADD_ITEM(
  499. ("File %s; Line %d # adding entry for model %s\n",
  500. __FILE__, __LINE__, model->Name()));
  501. entry = fNodeCache.AddItem(model->NodeRef());
  502. }
  503. ASSERT(entry);
  504. entry->SetIcon(bitmap, kNormalIcon, size);
  505. source = kVolume;
  506. } else {
  507. *resultingOpenCache = sharedCacheLocker;
  508. sharedCacheLocker->Lock();
  509. // If the volume doesnt have a device it should have
  510. // the generic icon
  511. entry = GetIconFromMetaMime(B_VOLUME_MIMETYPE, mode,
  512. size, lazyBitmap, entry);
  513. }
  514. }
  515. if (mode != kNormalIcon
  516. && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  517. entry->ConstructBitmap(mode, size, lazyBitmap);
  518. entry->SetIcon(lazyBitmap->Adopt(), mode, size);
  519. }
  520. return entry;
  521. }
  522. IconCacheEntry*
  523. IconCache::GetRootIcon(AutoLock<SimpleIconCache>*,
  524. AutoLock<SimpleIconCache>* sharedCacheLocker,
  525. AutoLock<SimpleIconCache>** resultingOpenCache,
  526. Model*, IconSource &source, IconDrawMode mode,
  527. icon_size size, LazyBitmapAllocator* lazyBitmap)
  528. {
  529. *resultingOpenCache = sharedCacheLocker;
  530. (*resultingOpenCache)->Lock();
  531. source = kTrackerSupplied;
  532. return GetIconFromMetaMime(B_ROOT_MIMETYPE, mode, size, lazyBitmap, 0);
  533. }
  534. IconCacheEntry*
  535. IconCache::GetWellKnownIcon(AutoLock<SimpleIconCache>*,
  536. AutoLock<SimpleIconCache>* sharedCacheLocker,
  537. AutoLock<SimpleIconCache>** resultingOpenCache,
  538. Model* model, IconSource &source, IconDrawMode mode, icon_size size,
  539. LazyBitmapAllocator* lazyBitmap)
  540. {
  541. const WellKnowEntryList::WellKnownEntry* wellKnownEntry
  542. = WellKnowEntryList::MatchEntry(model->NodeRef());
  543. if (!wellKnownEntry)
  544. return NULL;
  545. IconCacheEntry* entry = NULL;
  546. BString type("tracker/active_");
  547. type += wellKnownEntry->name;
  548. *resultingOpenCache = sharedCacheLocker;
  549. (*resultingOpenCache)->Lock();
  550. source = kTrackerSupplied;
  551. entry = fSharedCache.FindItem(type.String());
  552. if (entry) {
  553. entry = entry->ResolveIfAlias(&fSharedCache, entry);
  554. if (entry->HaveIconBitmap(mode, size))
  555. return entry;
  556. }
  557. if (!entry || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  558. // match up well known entries in the file system with specialized
  559. // icons stored in Tracker's resources
  560. int32 resid = -1;
  561. switch ((uint32)wellKnownEntry->which) {
  562. case B_BOOT_DISK:
  563. resid = R_BootVolumeIcon;
  564. break;
  565. case B_BEOS_DIRECTORY:
  566. resid = R_BeosFolderIcon;
  567. break;
  568. case B_USER_DIRECTORY:
  569. resid = R_HomeDirIcon;
  570. break;
  571. case B_BEOS_FONTS_DIRECTORY:
  572. case B_COMMON_FONTS_DIRECTORY:
  573. case B_USER_FONTS_DIRECTORY:
  574. resid = R_FontDirIcon;
  575. break;
  576. case B_BEOS_APPS_DIRECTORY:
  577. case B_APPS_DIRECTORY:
  578. case B_USER_DESKBAR_APPS_DIRECTORY:
  579. resid = R_AppsDirIcon;
  580. break;
  581. case B_BEOS_PREFERENCES_DIRECTORY:
  582. case B_PREFERENCES_DIRECTORY:
  583. case B_USER_DESKBAR_PREFERENCES_DIRECTORY:
  584. resid = R_PrefsDirIcon;
  585. break;
  586. case B_USER_MAIL_DIRECTORY:
  587. resid = R_MailDirIcon;
  588. break;
  589. case B_USER_QUERIES_DIRECTORY:
  590. resid = R_QueryDirIcon;
  591. break;
  592. case B_COMMON_DEVELOP_DIRECTORY:
  593. case B_USER_DESKBAR_DEVELOP_DIRECTORY:
  594. resid = R_DevelopDirIcon;
  595. break;
  596. case B_USER_CONFIG_DIRECTORY:
  597. resid = R_ConfigDirIcon;
  598. break;
  599. case B_USER_PEOPLE_DIRECTORY:
  600. resid = R_PersonDirIcon;
  601. break;
  602. case B_USER_DOWNLOADS_DIRECTORY:
  603. resid = R_DownloadDirIcon;
  604. break;
  605. default:
  606. return NULL;
  607. }
  608. entry = fSharedCache.AddItem(type.String());
  609. BBitmap* bitmap = lazyBitmap->Get();
  610. GetTrackerResources()->GetIconResource(resid, size, bitmap);
  611. entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size);
  612. }
  613. if (mode != kNormalIcon
  614. && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  615. entry->ConstructBitmap(mode, size, lazyBitmap);
  616. entry->SetIcon(lazyBitmap->Adopt(), mode, size);
  617. }
  618. ASSERT(entry->HaveIconBitmap(mode, size));
  619. return entry;
  620. }
  621. IconCacheEntry*
  622. IconCache::GetNodeIcon(ModelNodeLazyOpener* modelOpener,
  623. AutoLock<SimpleIconCache>* nodeCacheLocker,
  624. AutoLock<SimpleIconCache>** resultingOpenCache,
  625. Model* model, IconSource &source,
  626. IconDrawMode mode, icon_size size,
  627. LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry, bool permanent)
  628. {
  629. *resultingOpenCache = nodeCacheLocker;
  630. (*resultingOpenCache)->Lock();
  631. entry = fNodeCache.FindItem(model->NodeRef());
  632. if (!entry || !entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  633. modelOpener->OpenNode();
  634. BFile* file = NULL;
  635. // if we are dealing with an application, use the BAppFileInfo
  636. // superset of node; this makes GetIcon grab the proper icon for
  637. // an app
  638. if (model->IsExecutable())
  639. file = dynamic_cast<BFile*>(model->Node());
  640. PRINT_DISK_HITS(("File %s; Line %d # hitting disk for node %s\n",
  641. __FILE__, __LINE__, model->Name()));
  642. status_t result;
  643. if (file)
  644. result = GetAppIconFromAttr(file, lazyBitmap->Get(), size);
  645. else {
  646. result = GetFileIconFromAttr(model->Node(), lazyBitmap->Get(),
  647. size);
  648. }
  649. if (result == B_OK) {
  650. // node has it's own icon, use it
  651. BBitmap* bitmap = lazyBitmap->Adopt();
  652. PRINT_ADD_ITEM(("File %s; Line %d # adding entry for model %s\n",
  653. __FILE__, __LINE__, model->Name()));
  654. entry = fNodeCache.AddItem(model->NodeRef(), permanent);
  655. ASSERT(entry);
  656. entry->SetIcon(bitmap, kNormalIcon, size);
  657. if (mode != kNormalIcon) {
  658. entry->ConstructBitmap(mode, size, lazyBitmap);
  659. entry->SetIcon(lazyBitmap->Adopt(), mode, size);
  660. }
  661. source = kNode;
  662. }
  663. }
  664. if (!entry) {
  665. (*resultingOpenCache)->Unlock();
  666. *resultingOpenCache = NULL;
  667. } else if (!entry->HaveIconBitmap(mode, size)
  668. && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  669. entry->ConstructBitmap(mode, size, lazyBitmap);
  670. entry->SetIcon(lazyBitmap->Adopt(), mode, size);
  671. ASSERT(entry->HaveIconBitmap(mode, size));
  672. }
  673. return entry;
  674. }
  675. IconCacheEntry*
  676. IconCache::GetGenericIcon(AutoLock<SimpleIconCache>* sharedCacheLocker,
  677. AutoLock<SimpleIconCache>** resultingOpenCache,
  678. Model* model, IconSource &source,
  679. IconDrawMode mode, icon_size size,
  680. LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry)
  681. {
  682. *resultingOpenCache = sharedCacheLocker;
  683. (*resultingOpenCache)->Lock();
  684. entry = GetIconFromMetaMime(B_FILE_MIMETYPE, mode,
  685. size, lazyBitmap, 0);
  686. if (!entry)
  687. return NULL;
  688. // make an aliased entry so that the next time we get a
  689. // hit and substitute a generic icon right away
  690. PRINT_ADD_ITEM(
  691. ("File %s; Line %d # adding entry for preferredApp %s, type %s\n",
  692. __FILE__, __LINE__, model->PreferredAppSignature(),
  693. model->MimeType()));
  694. IconCacheEntry* aliasedEntry = fSharedCache.AddItem(
  695. (SharedCacheEntry**)&entry, model->MimeType(),
  696. model->PreferredAppSignature());
  697. aliasedEntry->SetAliasFor(&fSharedCache, (SharedCacheEntry*)entry);
  698. source = kMetaMime;
  699. ASSERT(entry->HaveIconBitmap(mode, size));
  700. return entry;
  701. }
  702. IconCacheEntry*
  703. IconCache::GetFallbackIcon(AutoLock<SimpleIconCache>* sharedCacheLocker,
  704. AutoLock<SimpleIconCache>** resultingOpenCache,
  705. Model* model, IconDrawMode mode, icon_size size,
  706. LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry)
  707. {
  708. *resultingOpenCache = sharedCacheLocker;
  709. (*resultingOpenCache)->Lock();
  710. entry = fSharedCache.AddItem(model->MimeType(),
  711. model->PreferredAppSignature());
  712. BBitmap* bitmap = lazyBitmap->Get();
  713. GetTrackerResources()->GetIconResource(R_FileIcon, size, bitmap);
  714. entry->SetIcon(lazyBitmap->Adopt(), kNormalIcon, size);
  715. if (mode != kNormalIcon) {
  716. entry->ConstructBitmap(mode, size, lazyBitmap);
  717. entry->SetIcon(lazyBitmap->Adopt(), mode, size);
  718. }
  719. ASSERT(entry->HaveIconBitmap(mode, size));
  720. return entry;
  721. }
  722. IconCacheEntry*
  723. IconCache::Preload(AutoLock<SimpleIconCache>* nodeCacheLocker,
  724. AutoLock<SimpleIconCache>* sharedCacheLocker,
  725. AutoLock<SimpleIconCache>** resultingCache,
  726. Model* model, IconDrawMode mode, icon_size size,
  727. bool permanent)
  728. {
  729. IconCacheEntry* entry = NULL;
  730. AutoLock<SimpleIconCache>* resultingOpenCache = NULL;
  731. // resultingOpenCache is the locker that points to the cache that
  732. // ended with a hit and will be used for the drawing
  733. { // scope for modelOpener
  734. ModelNodeLazyOpener modelOpener(model);
  735. // this opener takes care of opening the model and possibly
  736. // closing it when we are done
  737. LazyBitmapAllocator lazyBitmap(size);
  738. // lazyBitmap manages bitmap allocation and freeing if needed
  739. IconSource source = model->IconFrom();
  740. if (source == kUnknownSource || source == kUnknownNotFromNode) {
  741. // fish for special first models and handle them appropriately
  742. if (model->IsVolume()) {
  743. // volume may use specialized icon in the volume node
  744. entry = GetNodeIcon(&modelOpener, nodeCacheLocker,
  745. &resultingOpenCache, model, source, mode, size,
  746. &lazyBitmap, entry, permanent);
  747. if (!entry || !entry->HaveIconBitmap(mode, size))
  748. // look for volume defined icon
  749. entry = GetVolumeIcon(nodeCacheLocker, sharedCacheLocker,
  750. &resultingOpenCache, model, source, mode,
  751. size, &lazyBitmap);
  752. } else if (model->IsRoot()) {
  753. entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker,
  754. &resultingOpenCache, model, source, mode, size, &lazyBitmap);
  755. ASSERT(entry);
  756. } else {
  757. if (source == kUnknownSource)
  758. // look for node icons first
  759. entry = GetNodeIcon(&modelOpener, nodeCacheLocker,
  760. &resultingOpenCache, model, source,
  761. mode, size, &lazyBitmap, entry, permanent);
  762. if (!entry) {
  763. // no node icon, look for file type based one
  764. modelOpener.OpenNode();
  765. // use file types to get the icon
  766. resultingOpenCache = sharedCacheLocker;
  767. resultingOpenCache->Lock();
  768. entry = GetIconFromFileTypes(&modelOpener, source, mode, size,
  769. &lazyBitmap, 0);
  770. if (!entry) // we don't have an icon, go with the generic
  771. entry = GetGenericIcon(sharedCacheLocker, &resultingOpenCache,
  772. model, source, mode, size, &lazyBitmap, entry);
  773. }
  774. }
  775. // update the icon source
  776. model->SetIconFrom(source);
  777. } else {
  778. // we already know where the icon should come from,
  779. // use shortcuts to get it
  780. switch (source) {
  781. case kNode:
  782. resultingOpenCache = nodeCacheLocker;
  783. resultingOpenCache->Lock();
  784. entry = GetNodeIcon(&modelOpener, nodeCacheLocker,
  785. &resultingOpenCache, model, source, mode,
  786. size, &lazyBitmap, entry, permanent);
  787. if (entry) {
  788. entry = IconCacheEntry::ResolveIfAlias(&fSharedCache, entry);
  789. if (!entry->HaveIconBitmap(mode, size)
  790. && entry->HaveIconBitmap(NORMAL_ICON_ONLY, size)) {
  791. entry->ConstructBitmap(mode, size, &lazyBitmap);
  792. entry->SetIcon(lazyBitmap.Adopt(), mode, size);
  793. }
  794. ASSERT(entry->HaveIconBitmap(mode, size));
  795. }
  796. break;
  797. case kTrackerSupplied:
  798. if (model->IsRoot()) {
  799. entry = GetRootIcon(nodeCacheLocker, sharedCacheLocker,
  800. &resultingOpenCache, model, source, mode, size,
  801. &lazyBitmap);
  802. break;
  803. } else {
  804. entry = GetWellKnownIcon(nodeCacheLocker, sharedCacheLocker,
  805. &resultingOpenCache, model, source, mode, size,
  806. &lazyBitmap);
  807. if (entry)
  808. break;
  809. }
  810. // fall through
  811. case kTrackerDefault:
  812. case kVolume:
  813. if (model->IsVolume()) {
  814. entry = GetNodeIcon(&modelOpener, nodeCacheLocker,
  815. &resultingOpenCache, model, source,
  816. mode, size, &lazyBitmap, entry, permanent);
  817. if (!entry || !entry->HaveIconBitmap(mode, size))
  818. entry = GetVolumeIcon(nodeCacheLocker, sharedCacheLocker,
  819. &resultingOpenCache, model, source, mode, size,
  820. &lazyBitmap);
  821. break;
  822. }
  823. // fall through
  824. case kMetaMime:
  825. case kPreferredAppForType:
  826. case kPreferredAppForNode:
  827. resultingOpenCache = sharedCacheLocker;
  828. resultingOpenCache->Lock();
  829. entry = GetIconFromFileTypes(&modelOpener, source, mode, size,
  830. &lazyBitmap, 0);
  831. ASSERT(!entry || entry->HaveIconBitmap(mode, size));
  832. if (!entry || !entry->HaveIconBitmap(mode, size))
  833. // we don't have an icon, go with the generic
  834. entry = GetGenericIcon(sharedCacheLocker, &resultingOpenCache,
  835. model, source, mode, size, &lazyBitmap, entry);
  836. model->SetIconFrom(source);
  837. // the source shouldn't change in this case; if it does though we
  838. // might never be hitting the correct icon and instead keep leaking
  839. // entries after each miss
  840. // this now happens if an app defines an icon but a GetIconForType
  841. // fails and we fall back to generic icon
  842. // ToDo:
  843. // fix this and add an assert to the effect
  844. ASSERT(entry);
  845. ASSERT(entry->HaveIconBitmap(mode, size));
  846. break;
  847. default:
  848. TRESPASS();
  849. }
  850. }
  851. if (!entry || !entry->HaveIconBitmap(mode, size)) {
  852. // we don't have an icon, go with the generic
  853. PRINT(
  854. ("icon cache complete miss, falling back on generic icon "
  855. "for %s\n", model->Name()));
  856. entry = GetGenericIcon(sharedCacheLocker, &resultingOpenCache,
  857. model, source, mode, size, &lazyBitmap, entry);
  858. // we don't even have generic, something is really broken,
  859. // go with hardcoded generic icon
  860. if (!entry || !entry->HaveIconBitmap(mode, size)) {
  861. PRINT(
  862. ("icon cache complete miss, falling back on generic "
  863. "icon for %s\n", model->Name()));
  864. entry = GetFallbackIcon(sharedCacheLocker,
  865. &resultingOpenCache, model, mode, size, &lazyBitmap,
  866. entry);
  867. }
  868. // force icon pick up next time around because we probably just
  869. // hit a node in transition
  870. model->SetIconFrom(kUnknownSource);
  871. }
  872. }
  873. ASSERT(entry && entry->HaveIconBitmap(mode, size));
  874. if (resultingCache)
  875. *resultingCache = resultingOpenCache;
  876. return entry;
  877. }
  878. void
  879. IconCache::Draw(Model* model, BView* view, BPoint where, IconDrawMode mode,
  880. icon_size size, bool async)
  881. {
  882. // the following does not actually lock the caches, we are using the
  883. // lockLater mode; we will decide which of the two to lock down depending
  884. // on where we get the icon from
  885. AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false);
  886. AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false);
  887. AutoLock<SimpleIconCache>* resultingCacheLocker;
  888. IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker,
  889. &resultingCacheLocker, model, mode, size, false);
  890. // Preload finds/creates the appropriate entry, locking down the
  891. // cache it is in and returns the whole state back to here
  892. if (!entry)
  893. return;
  894. ASSERT(entry);
  895. ASSERT(entry->HaveIconBitmap(mode, size));
  896. // got the entry, now draw it
  897. resultingCacheLocker->LockedItem()->Draw(entry, view, where, mode,
  898. size, async);
  899. // either of the two cache lockers that got locked down by this call get
  900. // unlocked at this point
  901. }
  902. void
  903. IconCache::SyncDraw(Model* model, BView* view, BPoint where,
  904. IconDrawMode mode, icon_size size,
  905. void (*blitFunc)(BView*, BPoint, BBitmap*, void*),
  906. void* passThruState)
  907. {
  908. AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false);
  909. AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false);
  910. AutoLock<SimpleIconCache>* resultingCacheLocker;
  911. IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker,
  912. &resultingCacheLocker, model, mode, size, false);
  913. if (!entry)
  914. return;
  915. ASSERT(entry);
  916. ASSERT(entry->HaveIconBitmap(mode, size));
  917. resultingCacheLocker->LockedItem()->Draw(entry, view, where,
  918. mode, size, blitFunc, passThruState);
  919. }
  920. void
  921. IconCache::Preload(Model* model, IconDrawMode mode, icon_size size,
  922. bool permanent)
  923. {
  924. AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false);
  925. AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false);
  926. Preload(&nodeCacheLocker, &sharedCacheLocker, 0, model, mode, size,
  927. permanent);
  928. }
  929. status_t
  930. IconCache::Preload(const char* fileType, IconDrawMode mode, icon_size size)
  931. {
  932. AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache);
  933. LazyBitmapAllocator lazyBitmap(size);
  934. BMimeType mime(fileType);
  935. char preferredAppSig[B_MIME_TYPE_LENGTH];
  936. status_t result = mime.GetPreferredApp(preferredAppSig);
  937. if (result != B_OK)
  938. return result;
  939. // try getting the icon from the preferred app for the signature
  940. IconCacheEntry* entry = GetIconForPreferredApp(fileType, preferredAppSig,
  941. mode, size, &lazyBitmap, 0);
  942. if (entry)
  943. return B_OK;
  944. // try getting the icon directly from the metamime
  945. result = mime.GetIcon(lazyBitmap.Get(), size);
  946. if (result != B_OK)
  947. return result;
  948. entry = fSharedCache.AddItem(fileType);
  949. BBitmap* bitmap = lazyBitmap.Adopt();
  950. entry->SetIcon(bitmap, kNormalIcon, size);
  951. if (mode != kNormalIcon) {
  952. entry->ConstructBitmap(mode, size, &lazyBitmap);
  953. entry->SetIcon(lazyBitmap.Adopt(), mode, size);
  954. }
  955. return B_OK;
  956. }
  957. void
  958. IconCache::Deleting(const Model* model)
  959. {
  960. AutoLock<SimpleIconCache> lock(&fNodeCache);
  961. if (model->IconFrom() == kNode)
  962. fNodeCache.Deleting(model->NodeRef());
  963. // don't care if the node uses the shared cache
  964. }
  965. void
  966. IconCache::Removing(const Model* model)
  967. {
  968. AutoLock<SimpleIconCache> lock(&fNodeCache);
  969. if (model->IconFrom() == kNode)
  970. fNodeCache.Removing(model->NodeRef());
  971. }
  972. void
  973. IconCache::Deleting(const BView* view)
  974. {
  975. AutoLock<SimpleIconCache> lock(&fNodeCache);
  976. fNodeCache.Deleting(view);
  977. }
  978. void
  979. IconCache::IconChanged(Model* model)
  980. {
  981. AutoLock<SimpleIconCache> lock(&fNodeCache);
  982. if (model->IconFrom() == kNode || model->IconFrom() == kVolume)
  983. fNodeCache.Deleting(model->NodeRef());
  984. model->ResetIconFrom();
  985. }
  986. void
  987. IconCache::IconChanged(const char* mimeType, const char* appSignature)
  988. {
  989. AutoLock<SimpleIconCache> sharedLock(&fSharedCache);
  990. SharedCacheEntry* entry = fSharedCache.FindItem(mimeType, appSignature);
  991. if (!entry)
  992. return;
  993. AutoLock<SimpleIconCache> nodeLock(&fNodeCache);
  994. entry = (SharedCacheEntry*)fSharedCache.ResolveIfAlias(entry);
  995. ASSERT(entry);
  996. int32 index = fSharedCache.EntryIndex(entry);
  997. fNodeCache.RemoveAliasesTo(index);
  998. fSharedCache.RemoveAliasesTo(index);
  999. fSharedCache.IconChanged(entry);
  1000. }
  1001. BBitmap*
  1002. IconCache::MakeSelectedIcon(const BBitmap* normal, icon_size size,
  1003. LazyBitmapAllocator* lazyBitmap)
  1004. {
  1005. return MakeTransformedIcon(normal, size, fHiliteTable, lazyBitmap);
  1006. }
  1007. #if xDEBUG
  1008. static void
  1009. DumpBitmap(const BBitmap* bitmap)
  1010. {
  1011. if (!bitmap){
  1012. printf("NULL bitmap passed to DumpBitmap\n");
  1013. return;
  1014. }
  1015. int32 length = bitmap->BitsLength();
  1016. printf("data length %ld \n", length);
  1017. int32 columns = (int32)bitmap->Bounds().Width() + 1;
  1018. const unsigned char* bitPtr = (const unsigned char*)bitmap->Bits();
  1019. for (; length >= 0; length--) {
  1020. for (int32 columnIndex = 0; columnIndex < columns;
  1021. columnIndex++, length--)
  1022. printf("%c%c", "0123456789ABCDEF"[(*bitPtr)/0x10],
  1023. "0123456789ABCDEF"[(*bitPtr++)%0x10]);
  1024. printf("\n");
  1025. }
  1026. printf("\n");
  1027. }
  1028. #endif
  1029. void
  1030. IconCache::InitHiliteTable()
  1031. {
  1032. // build the color transform tables for different icon modes
  1033. BScreen screen(B_MAIN_SCREEN_ID);
  1034. rgb_color color;
  1035. for (int32 index = 0; index < kColorTransformTableSize; index++) {
  1036. color = screen.ColorForIndex((uchar)index);
  1037. fHiliteTable[index] = screen.IndexForColor(tint_color(color, 1.3f));
  1038. }
  1039. fHiliteTable[B_TRANSPARENT_8_BIT] = B_TRANSPARENT_8_BIT;
  1040. fInitHiliteTable = false;
  1041. }
  1042. BBitmap*
  1043. IconCache::MakeTransformedIcon(const BBitmap* source, icon_size /*size*/,
  1044. int32 colorTransformTable[], LazyBitmapAllocator* lazyBitmap)
  1045. {
  1046. if (fInitHiliteTable)
  1047. InitHiliteTable();
  1048. BBitmap* result = lazyBitmap->Get();
  1049. uint8* src = (uint8*)source->Bits();
  1050. uint8* dst = (uint8*)result->Bits();
  1051. // ASSERT(result->ColorSpace() == source->ColorSpace()
  1052. // && result->Bounds() == source->Bounds());
  1053. if (result->ColorSpace() != source->ColorSpace()
  1054. || result->Bounds() != source->Bounds()) {
  1055. printf("IconCache::MakeTransformedIcon() - "
  1056. "bitmap format mismatch!\n");
  1057. return NULL;
  1058. }
  1059. switch (result->ColorSpace()) {
  1060. case B_RGB32:
  1061. case B_RGBA32: {
  1062. uint32 width = source->Bounds().IntegerWidth() + 1;
  1063. uint32 height = source->Bounds().IntegerHeight() + 1;
  1064. uint32 srcBPR = source->BytesPerRow();
  1065. uint32 dstBPR = result->BytesPerRow();
  1066. for (uint32 y = 0; y < height; y++) {
  1067. uint8* d = dst;
  1068. uint8* s = src;
  1069. for (uint32 x = 0; x < width; x++) {
  1070. // 66% brightness
  1071. d[0] = (int)s[0] * 168 >> 8;
  1072. d[1] = (int)s[1] * 168 >> 8;
  1073. d[2] = (int)s[2] * 168 >> 8;
  1074. d[3] = s[3];
  1075. d += 4;
  1076. s += 4;
  1077. }
  1078. dst += dstBPR;
  1079. src += srcBPR;
  1080. }
  1081. break;
  1082. }
  1083. case B_CMAP8: {
  1084. int32 bitsLength = result->BitsLength();
  1085. for (int32 i = 0; i < bitsLength; i++)
  1086. *dst++ = (uint8)colorTransformTable[*src++];
  1087. break;
  1088. }
  1089. default:
  1090. memset(dst, 0, result->BitsLength());
  1091. // unkown colorspace, no tinting for you
  1092. // "black" should make the problem stand out
  1093. break;
  1094. }
  1095. return result;
  1096. }
  1097. bool
  1098. IconCache::IconHitTest(BPoint where, const Model* model, IconDrawMode mode,
  1099. icon_size size)
  1100. {
  1101. AutoLock<SimpleIconCache> nodeCacheLocker(&fNodeCache, false);
  1102. AutoLock<SimpleIconCache> sharedCacheLocker(&fSharedCache, false);
  1103. AutoLock<SimpleIconCache>* resultingCacheLocker;
  1104. IconCacheEntry* entry = Preload(&nodeCacheLocker, &sharedCacheLocker,
  1105. &resultingCacheLocker, const_cast<Model*>(model), mode, size, false);
  1106. // Preload finds/creates the appropriate entry, locking down the
  1107. // cache it is in and returns the whole state back to here
  1108. if (entry)
  1109. return entry->IconHitTest(where, mode, size);
  1110. return false;
  1111. }
  1112. void
  1113. IconCacheEntry::RetireIcons(BObjectList<BBitmap>* retiredBitmapList)
  1114. {
  1115. if (fLargeIcon) {
  1116. retiredBitmapList->AddItem(fLargeIcon);
  1117. fLargeIcon = NULL;
  1118. }
  1119. if (fMiniIcon) {
  1120. retiredBitmapList->AddItem(fMiniIcon);
  1121. fMiniIcon = NULL;
  1122. }
  1123. if (fHilitedLargeIcon) {
  1124. retiredBitmapList->AddItem(fHilitedLargeIcon);
  1125. fHilitedLargeIcon = NULL;
  1126. }
  1127. if (fHilitedMiniIcon) {
  1128. retiredBitmapList->AddItem(fHilitedMiniIcon);
  1129. fHilitedMiniIcon = NULL;
  1130. }
  1131. int32 count = retiredBitmapList->CountItems();
  1132. if (count > 10 * 1024) {
  1133. PRINT(("nuking old icons from the retired bitmap list\n"));
  1134. for (count = 512; count > 0; count--)
  1135. delete retiredBitmapList->RemoveItemAt(0);
  1136. }
  1137. }
  1138. // #pragma mark -
  1139. // In debug mode keep the hash table sizes small so that they grow a lot and
  1140. // execercise the resizing code a lot. In release mode allocate them large
  1141. // up-front for better performance
  1142. SharedIconCache::SharedIconCache()
  1143. #if DEBUG
  1144. : SimpleIconCache("Shared Icon cache aka \"The Dead-Locker\""),
  1145. fHashTable(20),
  1146. fElementArray(20),
  1147. fRetiredBitmaps(20, true)
  1148. #else
  1149. : SimpleIconCache("Tracker shared icon cache"),
  1150. fHashTable(1000),
  1151. fElementArray(1024),
  1152. fRetiredBitmaps(256, true)
  1153. #endif
  1154. {
  1155. fHashTable.SetElementVector(&fElementArray);
  1156. }
  1157. void
  1158. SharedIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where,
  1159. IconDrawMode mode, icon_size size, bool async)
  1160. {
  1161. ((SharedCacheEntry*)entry)->Draw(view, where, mode, size, async);
  1162. }
  1163. void
  1164. SharedIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where,
  1165. IconDrawMode mode, icon_size size, void (*blitFunc)(BView*, BPoint,
  1166. BBitmap*, void*), void* passThruState)
  1167. {
  1168. ((SharedCacheEntry*)entry)->Draw(view, where, mode, size,
  1169. blitFunc, passThruState);
  1170. }
  1171. SharedCacheEntry*
  1172. SharedIconCache::FindItem(const char* fileType,
  1173. const char* appSignature) const
  1174. {
  1175. ASSERT(fileType);
  1176. if (!fileType)
  1177. fileType = B_FILE_MIMETYPE;
  1178. SharedCacheEntry* result
  1179. = fHashTable.FindFirst(SharedCacheEntry::Hash(fileType,
  1180. appSignature));
  1181. if (!result)
  1182. return NULL;
  1183. for(;;) {
  1184. if (result->fFileType == fileType
  1185. && result->fAppSignature == appSignature) {
  1186. return result;
  1187. }
  1188. if (result->fNext < 0)
  1189. break;
  1190. result
  1191. = const_cast<SharedCacheEntry*>(&fElementArray.At(result->fNext));
  1192. }
  1193. return NULL;
  1194. }
  1195. SharedCacheEntry*
  1196. SharedIconCache::AddItem(const char* fileType, const char* appSignature)
  1197. {
  1198. ASSERT(fileType);
  1199. if (!fileType)
  1200. fileType = B_FILE_MIMETYPE;
  1201. SharedCacheEntry* result = fHashTable.Add(SharedCacheEntry::Hash(fileType,
  1202. appSignature));
  1203. result->SetTo(fileType, appSignature);
  1204. return result;
  1205. }
  1206. SharedCacheEntry*
  1207. SharedIconCache::AddItem(SharedCacheEntry** outstandingEntry,
  1208. const char* fileType, const char* appSignature)
  1209. {
  1210. int32 entryToken = fHashTable.ElementIndex(*outstandingEntry);
  1211. ASSERT(entryToken >= 0);
  1212. ASSERT(fileType);
  1213. if (!fileType)
  1214. fileType = B_FILE_MIMETYPE;
  1215. SharedCacheEntry* result = fHashTable.Add(SharedCacheEntry::Hash(fileType,
  1216. appSignature));
  1217. result->SetTo(fileType, appSignature);
  1218. *outstandingEntry = fHashTable.ElementAt(entryToken);
  1219. return result;
  1220. }
  1221. void
  1222. SharedIconCache::IconChanged(SharedCacheEntry* entry)
  1223. {
  1224. // by now there should be no aliases to entry, just remove entry
  1225. // itself
  1226. ASSERT(entry->fAliasForIndex == -1);
  1227. entry->RetireIcons(&fRetiredBitmaps);
  1228. fHashTable.Remove(entry);
  1229. }
  1230. void
  1231. SharedIconCache::RemoveAliasesTo(int32 aliasIndex)
  1232. {
  1233. int32 count = fHashTable.VectorSize();
  1234. for (int32 index = 0; index < count; index++) {
  1235. SharedCacheEntry* entry = fHashTable.ElementAt(index);
  1236. if (entry->fAliasForIndex == aliasIndex)
  1237. fHashTable.Remove(entry);
  1238. }
  1239. }
  1240. void
  1241. SharedIconCache::SetAliasFor(IconCacheEntry* alias,
  1242. const SharedCacheEntry* original) const
  1243. {
  1244. alias->fAliasForIndex = fHashTable.ElementIndex(original);
  1245. }
  1246. SharedCacheEntry::SharedCacheEntry()
  1247. : fNext(-1)
  1248. {
  1249. }
  1250. SharedCacheEntry::SharedCacheEntry(const char* fileType,
  1251. const char* appSignature)
  1252. : fNext(-1),
  1253. fFileType(fileType),
  1254. fAppSignature(appSignature)
  1255. {
  1256. }
  1257. void
  1258. SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode,
  1259. icon_size size, bool async)
  1260. {
  1261. BBitmap* bitmap = IconForMode(mode, size);
  1262. ASSERT(bitmap);
  1263. drawing_mode oldMode = view->DrawingMode();
  1264. if (bitmap->ColorSpace() == B_RGBA32) {
  1265. if (oldMode != B_OP_ALPHA) {
  1266. view->SetDrawingMode(B_OP_ALPHA);
  1267. view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
  1268. }
  1269. } else {
  1270. view->SetDrawingMode(B_OP_OVER);
  1271. }
  1272. if (async)
  1273. view->DrawBitmapAsync(bitmap, where);
  1274. else
  1275. view->DrawBitmap(bitmap, where);
  1276. view->SetDrawingMode(oldMode);
  1277. }
  1278. void
  1279. SharedCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode,
  1280. icon_size size, void (*blitFunc)(BView*, BPoint, BBitmap*, void*),
  1281. void* passThruState)
  1282. {
  1283. BBitmap* bitmap = IconForMode(mode, size);
  1284. if (!bitmap)
  1285. return;
  1286. // if (bitmap->ColorSpace() == B_RGBA32) {
  1287. // view->SetDrawingMode(B_OP_ALPHA);
  1288. // view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
  1289. // } else {
  1290. // view->SetDrawingMode(B_OP_OVER);
  1291. // }
  1292. (blitFunc)(view, where, bitmap, passThruState);
  1293. }
  1294. uint32
  1295. SharedCacheEntry::Hash(const char* fileType, const char* appSignature)
  1296. {
  1297. uint32 hash = HashString(fileType, 0);
  1298. if (appSignature && appSignature[0])
  1299. hash = HashString(appSignature, hash);
  1300. return hash;
  1301. }
  1302. uint32
  1303. SharedCacheEntry::Hash() const
  1304. {
  1305. uint32 hash = HashString(fFileType.String(), 0);
  1306. if (fAppSignature.Length())
  1307. hash = HashString(fAppSignature.String(), hash);
  1308. return hash;
  1309. }
  1310. bool
  1311. SharedCacheEntry::operator==(const SharedCacheEntry &entry) const
  1312. {
  1313. return fFileType == entry.FileType()
  1314. && fAppSignature == entry.AppSignature();
  1315. }
  1316. void
  1317. SharedCacheEntry::SetTo(const char* fileType, const char* appSignature)
  1318. {
  1319. fFileType = fileType;
  1320. fAppSignature = appSignature;
  1321. }
  1322. SharedCacheEntryArray::SharedCacheEntryArray(int32 initialSize)
  1323. : OpenHashElementArray<SharedCacheEntry>(initialSize)
  1324. {
  1325. }
  1326. SharedCacheEntry*
  1327. SharedCacheEntryArray::Add()
  1328. {
  1329. return OpenHashElementArray<SharedCacheEntry>::Add();
  1330. }
  1331. // #pragma mark -
  1332. NodeCacheEntry::NodeCacheEntry(bool permanent)
  1333. : fNext(-1),
  1334. fPermanent(permanent)
  1335. {
  1336. }
  1337. NodeCacheEntry::NodeCacheEntry(const node_ref* node, bool permanent)
  1338. : fNext(-1),
  1339. fRef(*node),
  1340. fPermanent(permanent)
  1341. {
  1342. }
  1343. void
  1344. NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode,
  1345. icon_size size, bool async)
  1346. {
  1347. BBitmap* bitmap = IconForMode(mode, size);
  1348. if (!bitmap)
  1349. return;
  1350. drawing_mode oldMode = view->DrawingMode();
  1351. if (bitmap->ColorSpace() == B_RGBA32) {
  1352. if (oldMode != B_OP_ALPHA) {
  1353. view->SetDrawingMode(B_OP_ALPHA);
  1354. view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
  1355. }
  1356. } else {
  1357. view->SetDrawingMode(B_OP_OVER);
  1358. }
  1359. if (false && async) {
  1360. TRESPASS();
  1361. // need to copy the bits first in here
  1362. view->DrawBitmapAsync(bitmap, where);
  1363. } else
  1364. view->DrawBitmap(bitmap, where);
  1365. view->SetDrawingMode(oldMode);
  1366. }
  1367. void
  1368. NodeCacheEntry::Draw(BView* view, BPoint where, IconDrawMode mode,
  1369. icon_size size, void (*blitFunc)(BView*, BPoint, BBitmap*, void*),
  1370. void* passThruState)
  1371. {
  1372. BBitmap* bitmap = IconForMode(mode, size);
  1373. if (!bitmap)
  1374. return;
  1375. // if (bitmap->ColorSpace() == B_RGBA32) {
  1376. // view->SetDrawingMode(B_OP_ALPHA);
  1377. // view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
  1378. // } else {
  1379. // view->SetDrawingMode(B_OP_OVER);
  1380. // }
  1381. (blitFunc)(view, where, bitmap, passThruState);
  1382. }
  1383. const node_ref*
  1384. NodeCacheEntry::Node() const
  1385. {
  1386. return &fRef;
  1387. }
  1388. uint32
  1389. NodeCacheEntry::Hash() const
  1390. {
  1391. return Hash(&fRef);
  1392. }
  1393. uint32
  1394. NodeCacheEntry::Hash(const node_ref* node)
  1395. {
  1396. return node->device ^ ((uint32*)&node->node)[0]
  1397. ^ ((uint32*)&node->node)[1];
  1398. }
  1399. bool
  1400. NodeCacheEntry::operator==(const NodeCacheEntry &entry) const
  1401. {
  1402. return fRef == entry.fRef;
  1403. }
  1404. void
  1405. NodeCacheEntry::SetTo(const node_ref* node)
  1406. {
  1407. fRef = *node;
  1408. }
  1409. bool
  1410. NodeCacheEntry::Permanent() const
  1411. {
  1412. return fPermanent;
  1413. }
  1414. void
  1415. NodeCacheEntry::MakePermanent()
  1416. {
  1417. fPermanent = true;
  1418. }
  1419. // #pragma mark -
  1420. NodeIconCache::NodeIconCache()
  1421. #if DEBUG
  1422. : SimpleIconCache("Node Icon cache aka \"The Dead-Locker\""),
  1423. fHashTable(20),
  1424. fElementArray(20)
  1425. #else
  1426. : SimpleIconCache("Tracker node icon cache"),
  1427. fHashTable(100),
  1428. fElementArray(100)
  1429. #endif
  1430. {
  1431. fHashTable.SetElementVector(&fElementArray);
  1432. }
  1433. void
  1434. NodeIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where,
  1435. IconDrawMode mode, icon_size size, bool async)
  1436. {
  1437. ((NodeCacheEntry*)entry)->Draw(view, where, mode, size, async);
  1438. }
  1439. void
  1440. NodeIconCache::Draw(IconCacheEntry* entry, BView* view, BPoint where,
  1441. IconDrawMode mode, icon_size size, void (*blitFunc)(BView*, BPoint,
  1442. BBitmap*, void*), void* passThruState)
  1443. {
  1444. ((NodeCacheEntry*)entry)->Draw(view, where, mode, size,
  1445. blitFunc, passThruState);
  1446. }
  1447. NodeCacheEntry*
  1448. NodeIconCache::FindItem(const node_ref* node) const
  1449. {
  1450. NodeCacheEntry* result = fHashTable.FindFirst(NodeCacheEntry::Hash(node));
  1451. if (!result)
  1452. return NULL;
  1453. for(;;) {
  1454. if (*result->Node() == *node)
  1455. return result;
  1456. if (result->fNext < 0)
  1457. break;
  1458. result
  1459. = const_cast<NodeCacheEntry*>(&fElementArray.At(result->fNext));
  1460. }
  1461. return NULL;
  1462. }
  1463. NodeCacheEntry*
  1464. NodeIconCache::AddItem(const node_ref* node, bool permanent)
  1465. {
  1466. NodeCacheEntry* result = fHashTable.Add(NodeCacheEntry::Hash(node));
  1467. result->SetTo(node);
  1468. if (permanent)
  1469. result->MakePermanent();
  1470. return result;
  1471. }
  1472. NodeCacheEntry*
  1473. NodeIconCache::AddItem(NodeCacheEntry** outstandingEntry,
  1474. const node_ref* node)
  1475. {
  1476. int32 entryToken = fHashTable.ElementIndex(*outstandingEntry);
  1477. NodeCacheEntry* result = fHashTable.Add(NodeCacheEntry::Hash(node));
  1478. result->SetTo(node);
  1479. *outstandingEntry = fHashTable.ElementAt(entryToken);
  1480. return result;
  1481. }
  1482. void
  1483. NodeIconCache::Deleting(const node_ref* node)
  1484. {
  1485. NodeCacheEntry* entry = FindItem(node);
  1486. ASSERT(entry);
  1487. if (!entry || entry->Permanent())
  1488. return;
  1489. fHashTable.Remove(entry);
  1490. }
  1491. void
  1492. NodeIconCache::Removing(const node_ref* node)
  1493. {
  1494. NodeCacheEntry* entry = FindItem(node);
  1495. ASSERT(entry);
  1496. if (!entry)
  1497. return;
  1498. fHashTable.Remove(entry);
  1499. }
  1500. void
  1501. NodeIconCache::Deleting(const BView*)
  1502. {
  1503. #ifdef NODE_CACHE_ASYNC_DRAWS
  1504. TRESPASS();
  1505. #endif
  1506. }
  1507. void
  1508. NodeIconCache::IconChanged(const Model* model)
  1509. {
  1510. Deleting(model->NodeRef());
  1511. }
  1512. void
  1513. NodeIconCache::RemoveAliasesTo(int32 aliasIndex)
  1514. {
  1515. int32 count = fHashTable.VectorSize();
  1516. for (int32 index = 0; index < count; index++) {
  1517. NodeCacheEntry* entry = fHashTable.ElementAt(index);
  1518. if (entry->fAliasForIndex == aliasIndex)
  1519. fHashTable.Remove(entry);
  1520. }
  1521. }
  1522. // #pragma mark -
  1523. NodeCacheEntryArray::NodeCacheEntryArray(int32 initialSize)
  1524. : OpenHashElementArray<NodeCacheEntry>(initialSize)
  1525. {
  1526. }
  1527. NodeCacheEntry*
  1528. NodeCacheEntryArray::Add()
  1529. {
  1530. return OpenHashElementArray<NodeCacheEntry>::Add();
  1531. }
  1532. // #pragma mark -
  1533. SimpleIconCache::SimpleIconCache(const char* name)
  1534. : fLock(name)
  1535. {
  1536. }
  1537. void
  1538. SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
  1539. icon_size, bool)
  1540. {
  1541. TRESPASS();
  1542. // pure virtual, do nothing
  1543. }
  1544. void
  1545. SimpleIconCache::Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
  1546. icon_size, void(*)(BView*, BPoint, BBitmap*, void*), void*)
  1547. {
  1548. TRESPASS();
  1549. // pure virtual, do nothing
  1550. }
  1551. bool
  1552. SimpleIconCache::Lock()
  1553. {
  1554. return fLock.Lock();
  1555. }
  1556. void
  1557. SimpleIconCache::Unlock()
  1558. {
  1559. fLock.Unlock();
  1560. }
  1561. bool
  1562. SimpleIconCache::IsLocked() const
  1563. {
  1564. return fLock.IsLocked();
  1565. }
  1566. // #pragma mark -
  1567. LazyBitmapAllocator::LazyBitmapAllocator(icon_size size,
  1568. color_space colorSpace, bool preallocate)
  1569. : fBitmap(NULL),
  1570. fSize(size),
  1571. fColorSpace(colorSpace)
  1572. {
  1573. if (preallocate)
  1574. Get();
  1575. }
  1576. LazyBitmapAllocator::~LazyBitmapAllocator()
  1577. {
  1578. delete fBitmap;
  1579. }
  1580. BBitmap*
  1581. LazyBitmapAllocator::Get()
  1582. {
  1583. if (!fBitmap)
  1584. fBitmap = new BBitmap(BRect(0, 0, fSize - 1, fSize - 1), fColorSpace);
  1585. return fBitmap;
  1586. }
  1587. BBitmap*
  1588. LazyBitmapAllocator::Adopt()
  1589. {
  1590. if (!fBitmap)
  1591. Get();
  1592. BBitmap* result = fBitmap;
  1593. fBitmap = NULL;
  1594. return result;
  1595. }
  1596. IconCache* IconCache::sIconCache;