xref: /haiku/src/kits/tracker/IconCache.h (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 #ifndef _NU_ICON_CACHE_H
35 #define _NU_ICON_CACHE_H
36 
37 
38 // Icon cache is used for drawing node icons; it caches icons
39 // and reuses them for successive draws
40 
41 
42 #include <Bitmap.h>
43 #include <ObjectList.h>
44 #include <Mime.h>
45 #include <String.h>
46 
47 #include "AutoLock.h"
48 #include "HashSet.h"
49 #include "Utilities.h"
50 
51 
52 // Icon cache splits icons into two caches - the shared cache, likely to
53 // get the most hits and the node cache. Every icon that is found in a
54 // mime-based structure goes into the shared cache, only files that have
55 // their own private icon use the node cache;
56 // Entries are only deleted from the shared cache if an icon for a mime type
57 // changes, this makes async icon drawing easier. Node cache deletes it's
58 // entries whenever a file gets deleted.
59 
60 // if a view ever uses the cache to draw in async mode, it needs to call
61 // it when it is being destroyed
62 
63 namespace BPrivate {
64 
65 class Model;
66 class ModelNodeLazyOpener;
67 class LazyBitmapAllocator;
68 class SharedIconCache;
69 class SharedCacheEntry;
70 class GenerateThumbnailJob;
71 
72 enum IconDrawMode {
73 	// Different states of icon drawing
74 	kSelected 					= 0x01,
75 	kNotFocused					= 0x02,		// Tracker window
76 	kOpen						= 0x04,		// open folder, trash
77 	kNotEmpty					= 0x08,		// full trash
78 	kDisabled					= 0x10,		// inactive nav menu entry
79 	kActive						= 0x20,		// active home dir, boot volume
80 	kLink						= 0x40,		// symbolic link
81 	kTrackerSpecialized			= 0x80,
82 
83 	// some common combinations
84 	kNormalIcon						= 0,
85 	kSelectedIcon					= kSelected,
86 	kSelectedInBackgroundIcon		= kSelected | kNotFocused,
87 	kOpenIcon						= kOpen,
88 	kOpenSelectedIcon				= kSelected | kOpen,
89 	kOpenSelectedInBackgroundIcon	= kSelected | kNotFocused | kOpen,
90 	kFullIcon						= kNotEmpty,
91 	kFullSelectedIcon				= kNotEmpty | kOpen,
92 	kDimmedIcon
93 };
94 
95 
96 #define NORMAL_ICON_ONLY kNormalIcon
97 	// replace use of these defines with mode once the respective getters
98 	// can get non-plain icons
99 
100 
101 // Where did an icon come from
102 enum IconSource {
103 	kUnknownSource,
104 	kUnknownNotFromNode,	// icon origin not known but determined not
105 							// to be from the node itself
106 	kTrackerDefault,		// file has no type, Tracker provides generic,
107 							// folder, symlink or app
108 	kTrackerSupplied,		// home directory, boot volume, trash, etc.
109 	kMetaMime,				// from BMimeType
110 	kPreferredAppForType,	// have a preferred application for a type,
111 							// has an icon
112 	kPreferredAppForNode,	// have a preferred application for this node,
113 							// has an icon
114 	kVolume,
115 	kNode
116 };
117 
118 
119 template<typename Class>
120 struct SelfHashing {
121 	typedef typename Class::HashKeyType KeyType;
122 	typedef Class ValueType;
123 
124 	size_t HashKey(KeyType key) const
125 	{
126 		return Class::Hash(key);
127 	}
128 
129 	size_t Hash(ValueType* value) const
130 	{
131 		return value->Hash();
132 	}
133 
134 	bool Compare(KeyType key, ValueType* value) const
135 	{
136 		return *value == key;
137 	}
138 
139 	ValueType*& GetLink(ValueType* value) const
140 	{
141 		return value->HashNext();
142 	}
143 };
144 
145 
146 class IconCacheEntry {
147 	// aliased entries don't own their icons, just point
148 	// to some other entry that does
149 
150 	// This is used for icons that are defined by a preferred app for
151 	// a metamime, types that do not have an icon get to point to
152 	// generic, etc.
153 
154 public:
155 	IconCacheEntry();
156 	~IconCacheEntry();
157 
158 	void SetAliasFor(const SharedIconCache* sharedCache,
159 		const SharedCacheEntry* entry);
160 	static IconCacheEntry* ResolveIfAlias(const SharedIconCache* sharedCache,
161 		IconCacheEntry* entry);
162 	IconCacheEntry* ResolveIfAlias(const SharedIconCache* sharedCache);
163 
164 	void SetIcon(BBitmap* bitmap, IconDrawMode mode, BSize size);
165 
166 	bool HaveIconBitmap(IconDrawMode mode, BSize size) const;
167 	bool CanConstructBitmap(IconDrawMode mode, BSize size) const;
168 	static bool AlternateModeForIconConstructing(IconDrawMode requestedMode,
169 		IconDrawMode &alternate, BSize size);
170 	BBitmap* ConstructBitmap(BBitmap* constructFrom,
171 		IconDrawMode requestedMode, IconDrawMode constructFromMode,
172 		BSize size, LazyBitmapAllocator*);
173 	BBitmap* ConstructBitmap(IconDrawMode requestedMode, BSize size,
174 		LazyBitmapAllocator*);
175 		// same as above, always uses normal icon as source
176 
177 	bool IconHitTest(BPoint, IconDrawMode, BSize) const;
178 		// given a point, returns true if a non-transparent pixel was hit
179 
180 	void RetireIcons(BObjectList<BBitmap>* retiredBitmapList);
181 		// can't just delete icons, they may be still drawing
182 		// async; instead, put them on the retired list and
183 		// only delete the list if it grows too much, way after
184 		// the icon finishes drawing
185 		//
186 		// This could fail if we retire a lot of icons (10 * 1024)
187 		// while we are drawing them, shouldn't be a practical problem
188 
189 protected:
190 	BBitmap* IconForMode(IconDrawMode mode, BSize size) const;
191 	void SetIconForMode(BBitmap* bitmap, IconDrawMode mode, BSize size);
192 
193 	// list of most common icons
194 	BBitmap* fLargeIcon;
195 	BBitmap* fHighlightedLargeIcon;
196 	BBitmap* fMiniIcon;
197 	BBitmap* fHighlightedMiniIcon;
198 
199 	const IconCacheEntry* fAliasTo;
200 
201 	// list of other icon kinds would be added here
202 
203 	friend class SharedIconCache;
204 	friend class NodeIconCache;
205 };
206 
207 
208 class SimpleIconCache {
209 public:
210 	SimpleIconCache(const char*);
211 	virtual ~SimpleIconCache() {}
212 
213 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode mode,
214 		BSize size, bool async = false) = 0;
215 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
216 		BSize, void (*)(BView*, BPoint, BBitmap*, void*),
217 		void* = NULL) = 0;
218 
219 	bool Lock();
220 	void Unlock();
221 	bool IsLocked() const;
222 
223 private:
224 	Benaphore fLock;
225 };
226 
227 
228 class SharedCacheEntry : public IconCacheEntry {
229 public:
230 	SharedCacheEntry();
231 	SharedCacheEntry(const char* fileType, const char* appSignature = 0);
232 
233 	void Draw(BView*, BPoint, IconDrawMode mode, BSize size,
234 		bool async = false);
235 
236 	void Draw(BView*, BPoint, IconDrawMode, BSize,
237 		void (*)(BView*, BPoint, BBitmap*, void*), void* = NULL);
238 
239 	const char* FileType() const;
240 	const char* AppSignature() const;
241 
242 public:
243 	// hash table support
244 	struct TypeAndSignature {
245 		const char* type, *signature;
246 		TypeAndSignature(const char* t, const char* s)
247 			: type(t), signature(s) {}
248 	};
249 	typedef TypeAndSignature HashKeyType;
250 	static size_t Hash(const TypeAndSignature& typeAndSignature);
251 
252 	size_t Hash() const;
253 	SharedCacheEntry*& HashNext() { return fNext; }
254 	bool operator==(const TypeAndSignature& typeAndSignature) const;
255 
256 private:
257 	SharedCacheEntry* fNext;
258 
259 	BString fFileType;
260 	BString fAppSignature;
261 
262 	friend class SharedIconCache;
263 };
264 
265 
266 class SharedIconCache : public SimpleIconCache {
267 	// SharedIconCache is used for icons that come from the mime database
268 public:
269 	SharedIconCache();
270 
271 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode mode,
272 		BSize size, bool async = false);
273 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
274 		BSize, void (*)(BView*, BPoint, BBitmap*, void*), void* = NULL);
275 
276 	SharedCacheEntry* FindItem(const char* fileType,
277 		const char* appSignature = 0) const;
278 	SharedCacheEntry* AddItem(const char* fileType,
279 		const char* appSignature = 0);
280 	void IconChanged(SharedCacheEntry*);
281 
282 	void SetAliasFor(IconCacheEntry* entry,
283 		const SharedCacheEntry* original) const;
284 	IconCacheEntry* ResolveIfAlias(IconCacheEntry* entry) const;
285 
286 	void RemoveAliasesTo(SharedCacheEntry* alias);
287 
288 private:
289 	typedef BOpenHashTable<SelfHashing<SharedCacheEntry> > EntryHashTable;
290 	EntryHashTable fHashTable;
291 
292 	BObjectList<BBitmap> fRetiredBitmaps;
293 		// icons are drawn asynchronously, can't just delete them right away,
294 		// instead have to place them onto the retired bitmap list and wait
295 		// for the next sync to delete them
296 };
297 
298 
299 class NodeCacheEntry : public IconCacheEntry {
300 public:
301 	NodeCacheEntry(bool permanent = false);
302 	NodeCacheEntry(const node_ref*, bool permanent = false);
303 	void Draw(BView*, BPoint, IconDrawMode mode, BSize size,
304 		bool async = false);
305 
306 	void Draw(BView*, BPoint, IconDrawMode, BSize,
307 		void (*)(BView*, BPoint, BBitmap*, void*), void* = NULL);
308 
309 	const node_ref* Node() const;
310 
311 	bool Permanent() const;
312 
313 public:
314 	// hash table support
315 	typedef const node_ref* HashKeyType;
316 	static size_t Hash(const node_ref* node);
317 
318 	size_t Hash() const;
319 	NodeCacheEntry*& HashNext() { return fNext; }
320 	bool operator==(const node_ref* ref) const;
321 
322 private:
323 	NodeCacheEntry* fNext;
324 
325 	node_ref fRef;
326 	bool fPermanent;
327 		// special cache entry that has to be deleted explicitly
328 
329 	friend class NodeIconCache;
330 };
331 
332 
333 class NodeIconCache : public SimpleIconCache {
334 	// NodeIconCache is used for nodes that define their own icons
335 public:
336 	NodeIconCache();
337 
338 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
339 		BSize, bool async = false);
340 
341 	virtual void Draw(IconCacheEntry*, BView*, BPoint, IconDrawMode,
342 		BSize, void (*)(BView*, BPoint, BBitmap*, void*), void* = 0);
343 
344 	NodeCacheEntry* FindItem(const node_ref*) const;
345 	NodeCacheEntry* AddItem(const node_ref*, bool permanent = false);
346 	void Deleting(const node_ref*);
347 		// model for this node is getting deleted
348 		// (not necessarily the node itself)
349 	void Removing(const node_ref*);
350 		// used by permanent NodeIconCache entries, when an entry gets deleted
351 	void Deleting(const BView*);
352 	void IconChanged(const Model*);
353 
354 	void RemoveAliasesTo(SharedCacheEntry* alias);
355 
356 private:
357 	typedef BOpenHashTable<SelfHashing<NodeCacheEntry> > EntryHashTable;
358 	EntryHashTable fHashTable;
359 };
360 
361 
362 const int32 kColorTransformTableSize = 256;
363 
364 
365 class IconCache {
366 public:
367 	IconCache();
368 
369 	void Draw(Model*, BView*, BPoint where, IconDrawMode mode,
370 		BSize size, bool async = false);
371 		// draw an icon for a model, load the icon from the appropriate
372 		// location if not cached already
373 
374 	void SyncDraw(Model*, BView*, BPoint, IconDrawMode,
375 		BSize, void (*)(BView*, BPoint, BBitmap*, void*),
376 		void* passThruState = 0);
377 		// draw an icon for a model, load the icon from the appropriate
378 		// location if not cached already; only works for sync draws,
379 		// once the call returns, the bitmap may be deleted
380 
381 	// preload calls used to ensure successive cache hit for the respective
382 	// icon, used for common tracker types, etc; Not calling these should only
383 	// cause a slowdown
384 	void Preload(Model*, IconDrawMode mode, BSize size,
385 		bool permanent = false);
386 	status_t Preload(const char* mimeType, IconDrawMode mode, BSize size);
387 
388 	void Deleting(const Model*);
389 		// hook to manage unloading icons for nodes that are going away
390 	void Removing(const Model* model);
391 		// used by permanent NodeIconCache entries, when an entry gets
392 		// deleted
393 	void Deleting(const BView*);
394 		// hook to manage deleting draw view caches for views that are
395 		// going away
396 
397 	// icon changed calls, used when a node or a file type has an icon changed
398 	// the icons for the node/file type will be flushed and re-cached during
399 	// the next draw
400 	void IconChanged(Model*);
401 	void IconChanged(const char* mimeType, const char* appSignature);
402 
403 	bool IsIconFrom(const Model*, const char* mimeType,
404 		const char* appSignature) const;
405 		// called when metamime database changed to figure out which models
406 		// to redraw
407 
408 	bool IconHitTest(BPoint, const Model*, IconDrawMode, BSize);
409 
410 	// utility calls for building specialized icons
411 	BBitmap* MakeSelectedIcon(const BBitmap* normal, BSize,
412 		LazyBitmapAllocator*);
413 
414 	static bool NeedsDeletionNotification(IconSource);
415 
416 	static IconCache* sIconCache;
417 	static BSize sMiniIconSize;
418 
419 private:
420 	// shared calls
421 	IconCacheEntry* Preload(AutoLock<SimpleIconCache>* nodeCache,
422 		AutoLock<SimpleIconCache>* sharedCache,
423 		AutoLock<SimpleIconCache>** resultingLockedCache,
424 		Model*, IconDrawMode mode, BSize size, bool permanent);
425 		// preload uses lazy locking, returning the cache we decided
426 		// to use to get the icon
427 		// <resultingLockedCache> may be null if we don't care
428 
429 	// shared mime-based icon retrieval calls
430 	IconCacheEntry* GetIconForPreferredApp(const char* mimeTypeSignature,
431 		const char* preferredApp, IconDrawMode mode, BSize size,
432 		 LazyBitmapAllocator*, IconCacheEntry*);
433 	IconCacheEntry* GetIconFromFileTypes(ModelNodeLazyOpener*,
434 		IconSource &source, IconDrawMode mode, BSize size,
435 		LazyBitmapAllocator*, IconCacheEntry*);
436 	IconCacheEntry* GetIconFromMetaMime(const char* fileType,
437 		IconDrawMode mode, BSize size, LazyBitmapAllocator*,
438 		IconCacheEntry*);
439 	IconCacheEntry* GetVolumeIcon(AutoLock<SimpleIconCache>* nodeCache,
440 		AutoLock<SimpleIconCache>* sharedCache,
441 		AutoLock<SimpleIconCache>** resultingLockedCache,
442 		Model*, IconSource&, IconDrawMode mode,
443 		BSize size, LazyBitmapAllocator*);
444 	IconCacheEntry* GetRootIcon(AutoLock<SimpleIconCache>* nodeCache,
445 		AutoLock<SimpleIconCache>* sharedCache,
446 		AutoLock<SimpleIconCache>** resultingLockedCache,
447 		Model*, IconSource&, IconDrawMode mode,
448 		BSize size, LazyBitmapAllocator*);
449 	IconCacheEntry* GetWellKnownIcon(AutoLock<SimpleIconCache> *nodeCache,
450 		AutoLock<SimpleIconCache>* sharedCache,
451 		AutoLock<SimpleIconCache>** resultingLockedCache,
452 		Model*, IconSource&, IconDrawMode mode,
453 		BSize size, LazyBitmapAllocator*);
454 	IconCacheEntry* GetNodeIcon(ModelNodeLazyOpener *,
455 		AutoLock<SimpleIconCache>* nodeCache,
456 		AutoLock<SimpleIconCache>** resultingLockedCache,
457 		Model*, IconSource&, IconDrawMode mode,
458 		BSize size, LazyBitmapAllocator*, IconCacheEntry*,
459 		bool permanent);
460 	IconCacheEntry* GetGenericIcon(AutoLock<SimpleIconCache>* sharedCache,
461 		AutoLock<SimpleIconCache>** resultingLockedCache,
462 		Model*, IconSource&, IconDrawMode mode,
463 		BSize size, LazyBitmapAllocator*, IconCacheEntry*);
464 	IconCacheEntry* GetFallbackIcon(
465 		AutoLock<SimpleIconCache>* sharedCacheLocker,
466 		AutoLock<SimpleIconCache>** resultingOpenCache,
467 		Model* model, IconDrawMode mode, BSize size,
468 		LazyBitmapAllocator* lazyBitmap, IconCacheEntry* entry);
469 
470 	BBitmap* MakeTransformedIcon(const BBitmap*, BSize,
471 		int32 colorTransformTable [], LazyBitmapAllocator*);
472 
473 private:
474 	NodeIconCache fNodeCache;
475 	SharedIconCache fSharedCache;
476 
477 	void InitHighlightTable();
478 
479 	int32 fHighlightTable[kColorTransformTableSize];
480 	bool fInitHighlightTable;
481 		// whether or not we need to initialize the highlight table
482 
483 	friend class BPrivate::GenerateThumbnailJob;
484 };
485 
486 
487 class LazyBitmapAllocator {
488 	// Utility class used when we aren't sure that we will keep a bitmap,
489 	// need a bitmap or be able to construct it properly
490 public:
491 	LazyBitmapAllocator(BSize size,
492 		color_space colorSpace = kDefaultIconDepth,
493 		bool preallocate = false);
494 	~LazyBitmapAllocator();
495 
496 	BBitmap* Get();
497 	BBitmap* Adopt();
498 
499 private:
500 	BBitmap* fBitmap;
501 	BSize fSize;
502 	color_space fColorSpace;
503 };
504 
505 
506 // inlines follow
507 
508 inline const char*
509 SharedCacheEntry::FileType() const
510 {
511 	return fFileType.String();
512 }
513 
514 
515 inline const char*
516 SharedCacheEntry::AppSignature() const
517 {
518 	return fAppSignature.String();
519 }
520 
521 
522 inline bool
523 IconCache::NeedsDeletionNotification(IconSource from)
524 {
525 	return from == kNode;
526 }
527 
528 
529 inline IconCacheEntry*
530 SharedIconCache::ResolveIfAlias(IconCacheEntry* entry) const
531 {
532 	if (entry->fAliasTo == NULL)
533 		return entry;
534 
535 	return const_cast<IconCacheEntry*>(entry->fAliasTo);
536 }
537 
538 
539 } // namespace BPrivate
540 
541 using namespace BPrivate;
542 
543 
544 #endif	// _NU_ICON_CACHE_H
545