1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30of Be Incorporated in the United States and other countries. Other brand product
31names are registered trademarks or trademarks of their respective holders.
32All 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
63namespace BPrivate {
64
65class Model;
66class ModelNodeLazyOpener;
67class LazyBitmapAllocator;
68class SharedIconCache;
69class SharedCacheEntry;
70class GenerateThumbnailJob;
71
72enum 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
102enum 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
119template<typename Class>
120struct 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
146class 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
154public:
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
189protected:
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
208class SimpleIconCache {
209public:
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
223private:
224	Benaphore fLock;
225};
226
227
228class SharedCacheEntry : public IconCacheEntry {
229public:
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
242public:
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
256private:
257	SharedCacheEntry* fNext;
258
259	BString fFileType;
260	BString fAppSignature;
261
262	friend class SharedIconCache;
263};
264
265
266class SharedIconCache : public SimpleIconCache {
267	// SharedIconCache is used for icons that come from the mime database
268public:
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
288private:
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
299class NodeCacheEntry : public IconCacheEntry {
300public:
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
313public:
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
322private:
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
333class NodeIconCache : public SimpleIconCache {
334	// NodeIconCache is used for nodes that define their own icons
335public:
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
356private:
357	typedef BOpenHashTable<SelfHashing<NodeCacheEntry> > EntryHashTable;
358	EntryHashTable fHashTable;
359};
360
361
362const int32 kColorTransformTableSize = 256;
363
364
365class IconCache {
366public:
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
419private:
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
473private:
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
487class 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
490public:
491	LazyBitmapAllocator(BSize size,
492		color_space colorSpace = kDefaultIconDepth,
493		bool preallocate = false);
494	~LazyBitmapAllocator();
495
496	BBitmap* Get();
497	BBitmap* Adopt();
498
499private:
500	BBitmap* fBitmap;
501	BSize fSize;
502	color_space fColorSpace;
503};
504
505
506// inlines follow
507
508inline const char*
509SharedCacheEntry::FileType() const
510{
511	return fFileType.String();
512}
513
514
515inline const char*
516SharedCacheEntry::AppSignature() const
517{
518	return fAppSignature.String();
519}
520
521
522inline bool
523IconCache::NeedsDeletionNotification(IconSource from)
524{
525	return from == kNode;
526}
527
528
529inline IconCacheEntry*
530SharedIconCache::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
541using namespace BPrivate;
542
543
544#endif	// _NU_ICON_CACHE_H
545