summaryrefslogtreecommitdiff
path: root/platform/windows/mupdfwinrt/Cache.cpp
blob: d5108a7cf62eed5e7d134d6f381a7928a68562a3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "pch.h"
#include "Cache.h"

Cache::Cache(void)
{
	this->size = 0;
	this->head = NULL;
	this->tail = NULL;
}

Cache::~Cache(void)
{
}

void Cache::Empty(fz_context *mu_ctx)
{
	if (this != nullptr) {
		cache_entry_t *curr_entry = this->head;

		while (curr_entry != NULL)
		{
			cache_entry_t *old_entry = curr_entry;
			curr_entry = old_entry->next;
			fz_drop_display_list(mu_ctx, old_entry->dlist);
			delete old_entry;
		}
		this->size = 0;
		this->head = NULL;
		this->tail = NULL;
	}
}

void Cache::Add(int value, int width_in, int height_in, fz_display_list *dlist, 
				fz_context *mu_ctx)
{
	std::lock_guard<std::mutex> lock(cache_lock);

	/* If full, then delete the tail */
	if (size >= MAX_DISPLAY_CACHE_SIZE)
	{
		cache_entry_t *curr_entry = this->tail;
		cache_entry_t *prev_entry = curr_entry->prev;

		if (prev_entry != NULL)
			prev_entry->next = NULL;
		else
			head = NULL;

		tail = prev_entry;

		/* Decrement the caches rc of this list. It is gone from cache but
		   may still be in use by other threads, when threads are done they 
		   should decrement and it should be freed at that time. See 
		   ReleaseDisplayLists in muctx class */
		fz_drop_display_list(mu_ctx, curr_entry->dlist);
		delete curr_entry;
		size--;
	}

	/* Make a new entry and stick at head */
	cache_entry_t *new_entry = new cache_entry_t;

	new_entry->dlist = dlist;
	new_entry->index = value;
	new_entry->width = width_in;
	new_entry->height = height_in;
	new_entry->prev = NULL;
	if (head == NULL)
	{
		new_entry->next = NULL;
		head = new_entry;
		tail = new_entry;
	}
	else
	{
		new_entry->next = head;
		head->prev = new_entry;
		head = new_entry;
	}
	size++;
	/* Everytime we add an entry, we are also using it. Increment rc. See above */
	fz_keep_display_list(mu_ctx, dlist);
}

fz_display_list* Cache::Use(int value, int *width_out, int *height_out, fz_context *mu_ctx)
{
	std::lock_guard<std::mutex> lock(cache_lock);
	cache_entry_t *curr_entry = this->head;

	while (curr_entry != NULL)
	{
		if (curr_entry->index == value)
			break;
		curr_entry = curr_entry->next;
	}
	if (curr_entry != NULL)
	{
		/* Move this to the front */
		if (curr_entry != head)
		{
			cache_entry_t *prev_entry = curr_entry->prev;
			cache_entry_t *next_entry = curr_entry->next;
			prev_entry->next = next_entry;

			if (next_entry != NULL)
				next_entry->prev = prev_entry;
			else
				tail = prev_entry;

			curr_entry->prev = NULL;
			curr_entry->next = head;
			head->prev = curr_entry;
			head = curr_entry;
		}
		*width_out = curr_entry->width;
		*height_out = curr_entry->height;
		/* We must increment our reference to this one to ensure it is not 
		   freed when removed from the cache. See above comments */
		fz_keep_display_list(mu_ctx, curr_entry->dlist);
		return curr_entry->dlist;
	}
	else
		return NULL;
}