webrender/
api_resources.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use 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
18/// We use this to generate the async blob rendering requests.
19struct BlobImageTemplate {
20    descriptor: ImageDescriptor,
21    tile_size: TileSize,
22    dirty_rect: BlobDirtyRect,
23    /// See ImageResource::visible_rect.
24    visible_rect: DeviceIntRect,
25    // If the active rect of the blob changes, this represents the
26    // range of tiles that remain valid. This must be taken into
27    // account in addition to the valid rect when submitting blob
28    // rasterization requests.
29    // `None` means the bounds have not changed (tiles are still valid).
30    // `Some(TileRange::zero())` means all of the tiles are invalid.
31    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    // This should only be true for CI or debugging purposes. If true,
39    // we'll restrict the size of blob images as a result effectively
40    // rendering them incorrectly.
41    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                    // AddFontInstance will only be processed here, not in the resource cache, so it
140                    // is safe to take the options rather than clone them.
141                    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                    // We will delete from the shared font instance map in the resource cache
159                    // after scene swap.
160                }
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            // make sure the descriptor size matches the visible rect.
225            // This might not be necessary but let's stay on the safe side.
226            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            // If we know that only a portion of the blob image is in the viewport,
251            // only request these visible tiles since blob images can be huge.
252            let tiles = compute_tile_range(
253                &template.visible_rect,
254                template.tile_size,
255            );
256
257            // Don't request tiles that weren't invalidated.
258            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}