1use crate::api::{BlobImageKey, ImageDescriptor, DirtyRect, TileSize, DebugFlags};
6use crate::api::{BlobImageHandler, AsyncBlobImageRasterizer, BlobImageData, BlobImageParams};
7use crate::api::{BlobImageRequest, BlobImageDescriptor, FontTemplate};
8use crate::api::units::*;
9use glyph_rasterizer::{SharedFontResources, BaseFontInstance};
10use crate::render_api::{ResourceUpdate, TransactionMsg, AddFont};
11use crate::image_tiling::*;
12use crate::profiler;
13
14use std::collections::HashMap;
15use std::mem;
16use std::sync::Arc;
17
18struct BlobImageTemplate {
20 descriptor: ImageDescriptor,
21 tile_size: TileSize,
22 dirty_rect: BlobDirtyRect,
23 visible_rect: DeviceIntRect,
25 valid_tiles_after_bounds_change: Option<TileRange>,
32}
33
34pub struct ApiResources {
35 blob_image_templates: HashMap<BlobImageKey, BlobImageTemplate>,
36 pub blob_image_handler: Option<Box<dyn BlobImageHandler>>,
37 fonts: SharedFontResources,
38 debug_restrict_blob_size: bool,
42}
43
44impl ApiResources {
45 pub fn new(
46 blob_image_handler: Option<Box<dyn BlobImageHandler>>,
47 fonts: SharedFontResources,
48 ) -> Self {
49 ApiResources {
50 blob_image_templates: HashMap::new(),
51 blob_image_handler,
52 fonts,
53 debug_restrict_blob_size: false,
54 }
55 }
56
57 pub fn get_fonts(&self) -> SharedFontResources {
58 self.fonts.clone()
59 }
60
61 pub fn set_debug_flags(&mut self, flags: DebugFlags) {
62 self.debug_restrict_blob_size = flags.contains(DebugFlags::RESTRICT_BLOB_SIZE);
63 }
64
65 pub fn adjust_blob_visible_rect(&self, rect: &mut DeviceIntRect, size: Option<&mut DeviceIntSize>) {
66 if self.debug_restrict_blob_size {
67 rect.max.x = rect.max.x.min(rect.min.x + 2048);
68 rect.max.y = rect.max.y.min(rect.min.y + 2048);
69 if let Some(size) = size {
70 size.width = size.width.min(2048);
71 size.height = size.height.min(2048);
72 }
73 }
74 }
75
76 pub fn update(&mut self, transaction: &mut TransactionMsg) {
77 let mut blobs_to_rasterize = Vec::new();
78 for update in &mut transaction.resource_updates {
79 match *update {
80 ResourceUpdate::AddBlobImage(ref mut img) => {
81 self.adjust_blob_visible_rect(&mut img.visible_rect, Some(&mut img.descriptor.size));
82 self.blob_image_handler
83 .as_mut()
84 .expect("no blob image handler")
85 .add(img.key, Arc::clone(&img.data), &img.visible_rect, img.tile_size);
86
87 self.blob_image_templates.insert(
88 img.key,
89 BlobImageTemplate {
90 descriptor: img.descriptor,
91 tile_size: img.tile_size,
92 dirty_rect: DirtyRect::All,
93 valid_tiles_after_bounds_change: None,
94 visible_rect: img.visible_rect,
95 },
96 );
97 blobs_to_rasterize.push(img.key);
98 }
99 ResourceUpdate::UpdateBlobImage(ref mut img) => {
100 debug_assert_eq!(img.visible_rect.size(), img.descriptor.size);
101 self.adjust_blob_visible_rect(&mut img.visible_rect, Some(&mut img.descriptor.size));
102 self.update_blob_image(
103 img.key,
104 Some(&img.descriptor),
105 Some(&img.dirty_rect),
106 Some(Arc::clone(&img.data)),
107 &img.visible_rect,
108 );
109 blobs_to_rasterize.push(img.key);
110 }
111 ResourceUpdate::DeleteBlobImage(key) => {
112 transaction.use_scene_builder_thread = true;
113 self.blob_image_templates.remove(&key);
114 if let Some(ref mut handler) = self.blob_image_handler {
115 handler.delete(key);
116 }
117 }
118 ResourceUpdate::SetBlobImageVisibleArea(ref key, ref mut area) => {
119 self.adjust_blob_visible_rect(area, None);
120 self.update_blob_image(*key, None, None, None, &area);
121 blobs_to_rasterize.push(*key);
122 }
123 ResourceUpdate::AddFont(ref font) => {
124 let (key, template) = match font {
125 AddFont::Raw(key, bytes, index) => {
126 (key, FontTemplate::Raw(Arc::clone(bytes), *index))
127 }
128 AddFont::Native(key, native_font_handle) => {
129 (key, FontTemplate::Native(native_font_handle.clone()))
130 }
131 };
132 if let Some(shared_key) = self.fonts.font_keys.add_key(key, &template) {
133 self.fonts.templates.add_font(shared_key, template);
134 }
135 }
136 ResourceUpdate::AddFontInstance(ref mut instance) => {
137 let shared_font_key = self.fonts.font_keys.map_key(&instance.font_key);
138 assert!(self.fonts.templates.has_font(&shared_font_key));
139 let base = BaseFontInstance::new(
142 instance.key,
143 shared_font_key,
144 instance.glyph_size,
145 mem::take(&mut instance.options),
146 mem::take(&mut instance.platform_options),
147 mem::take(&mut instance.variations),
148 );
149 if let Some(shared_instance) = self.fonts.instance_keys.add_key(base) {
150 self.fonts.instances.add_font_instance(shared_instance);
151 }
152 }
153 ResourceUpdate::DeleteFont(_key) => {
154 transaction.use_scene_builder_thread = true;
155 }
156 ResourceUpdate::DeleteFontInstance(_key) => {
157 transaction.use_scene_builder_thread = true;
158 }
161 ResourceUpdate::DeleteImage(..) => {
162 transaction.use_scene_builder_thread = true;
163 }
164 _ => {}
165 }
166 }
167
168 let (rasterizer, requests) = self.create_blob_scene_builder_requests(&blobs_to_rasterize);
169 transaction.profile.set(profiler::RASTERIZED_BLOBS, blobs_to_rasterize.len());
170 transaction.profile.set(profiler::RASTERIZED_BLOB_TILES, requests.len());
171 transaction.use_scene_builder_thread |= !requests.is_empty();
172 transaction.use_scene_builder_thread |= !transaction.scene_ops.is_empty();
173 transaction.blob_rasterizer = rasterizer;
174 transaction.blob_requests = requests;
175 }
176
177 pub fn enable_multithreading(&mut self, enable: bool) {
178 if let Some(ref mut handler) = self.blob_image_handler {
179 handler.enable_multithreading(enable);
180 }
181 }
182
183 fn update_blob_image(
184 &mut self,
185 key: BlobImageKey,
186 descriptor: Option<&ImageDescriptor>,
187 dirty_rect: Option<&BlobDirtyRect>,
188 data: Option<Arc<BlobImageData>>,
189 visible_rect: &DeviceIntRect,
190 ) {
191 if let Some(data) = data {
192 let dirty_rect = dirty_rect.expect("no dirty rect");
193 self.blob_image_handler
194 .as_mut()
195 .expect("no blob image handler")
196 .update(key, data, visible_rect, dirty_rect);
197 }
198
199 let image = self.blob_image_templates
200 .get_mut(&key)
201 .expect("Attempt to update non-existent blob image");
202
203 let mut valid_tiles_after_bounds_change = compute_valid_tiles_if_bounds_change(
204 &image.visible_rect,
205 visible_rect,
206 image.tile_size,
207 );
208
209 match (image.valid_tiles_after_bounds_change, valid_tiles_after_bounds_change) {
210 (Some(old), Some(ref mut new)) => {
211 *new = new.intersection(&old).unwrap_or_else(TileRange::zero);
212 }
213 (Some(old), None) => {
214 valid_tiles_after_bounds_change = Some(old);
215 }
216 _ => {}
217 }
218
219 let blob_size = visible_rect.size();
220
221 if let Some(descriptor) = descriptor {
222 image.descriptor = *descriptor;
223 } else {
224 image.descriptor.size = blob_size;
227 }
228
229 if let Some(dirty_rect) = dirty_rect {
230 image.dirty_rect = image.dirty_rect.union(dirty_rect);
231 }
232
233 image.valid_tiles_after_bounds_change = valid_tiles_after_bounds_change;
234 image.visible_rect = *visible_rect;
235 }
236
237 pub fn create_blob_scene_builder_requests(
238 &mut self,
239 keys: &[BlobImageKey]
240 ) -> (Option<Box<dyn AsyncBlobImageRasterizer>>, Vec<BlobImageParams>) {
241 if self.blob_image_handler.is_none() || keys.is_empty() {
242 return (None, Vec::new());
243 }
244
245 let mut blob_request_params = Vec::new();
246 for key in keys {
247 let template = self.blob_image_templates.get_mut(key)
248 .expect("no blob image template");
249
250 let tiles = compute_tile_range(
253 &template.visible_rect,
254 template.tile_size,
255 );
256
257 let dirty_tiles = match template.dirty_rect {
259 DirtyRect::Partial(dirty_rect) => {
260 compute_tile_range(
261 &dirty_rect.cast_unit(),
262 template.tile_size,
263 )
264 }
265 DirtyRect::All => tiles,
266 };
267
268 for_each_tile_in_range(&tiles, |tile| {
269 let still_valid = template.valid_tiles_after_bounds_change
270 .map(|valid_tiles| valid_tiles.contains(tile))
271 .unwrap_or(true);
272
273 if still_valid && !dirty_tiles.contains(tile) {
274 return;
275 }
276
277 let descriptor = BlobImageDescriptor {
278 rect: compute_tile_rect(
279 &template.visible_rect,
280 template.tile_size,
281 tile,
282 ).cast_unit(),
283 format: template.descriptor.format,
284 };
285
286 assert!(descriptor.rect.width() > 0 && descriptor.rect.height() > 0);
287 blob_request_params.push(
288 BlobImageParams {
289 request: BlobImageRequest { key: *key, tile },
290 descriptor,
291 dirty_rect: DirtyRect::All,
292 }
293 );
294 });
295
296 template.dirty_rect = DirtyRect::empty();
297 template.valid_tiles_after_bounds_change = None;
298 }
299
300 let handler = self.blob_image_handler.as_mut()
301 .expect("no blob image handler");
302 handler.prepare_resources(&self.fonts, &blob_request_params);
303 (Some(handler.create_blob_rasterizer()), blob_request_params)
304 }
305}