|
| 1 | +let rec find_first_aux arr test low high = |
| 2 | + if low = high then high |
| 3 | + else ( |
| 4 | + let mid = (low + high) / 2 in |
| 5 | + let diff = test mid in |
| 6 | + if diff >= 0. then find_first_aux arr test low mid |
| 7 | + else find_first_aux arr test (mid + 1) high |
| 8 | + ) |
| 9 | + |
| 10 | +(* Binary search. Return the index of the first element where [test i] is true. |
| 11 | + If [test] isn't true for any element, returns the length of the array. |
| 12 | + Assumes that if [test i] then it's true for all later entries. *) |
| 13 | +let find_first ?(start = 0) arr test = |
| 14 | + find_first_aux arr test start (Array.length arr) |
| 15 | + |
1 | 16 | module type CANVAS = sig |
2 | 17 | type context |
3 | 18 |
|
@@ -215,63 +230,86 @@ module Make (C : CANVAS) = struct |
215 | 230 | in |
216 | 231 | C.paint_text cr ~x:(x +. 2.) ~y:(y +. 8.) ~clip_area:(clip_width -. 2., v.height) label |
217 | 232 |
|
| 233 | + let min_render_width = 0.2 |
| 234 | + |
| 235 | + (* Call [fn] for each event in the visible region, plus one on each side (if any). |
| 236 | + Very close events (at the current zoom level) are skipped. |
| 237 | + The caller will typically render the region ending in this event. *) |
218 | 238 | let iter_gc_spans v fn ring = |
219 | 239 | let arr = ring.Layout.Ring.events in |
220 | | - (* todo: binary search *) |
221 | | - for i = 0 to Array.length arr - 1 do |
222 | | - let time, e = arr.(i) in |
223 | | - fn (time, e) |
224 | | - done; |
225 | | - fn (v.View.layout.duration, []) |
| 240 | + let time_of i = fst arr.(i) in |
| 241 | + let start = max 0 (find_first arr (fun i -> time_of i -. v.View.start_time) - 1) in |
| 242 | + let stop_time = View.time_of_x v v.width in |
| 243 | + let stop = min (Array.length arr) (1 + find_first arr (fun i -> time_of i -. stop_time) ~start) in |
| 244 | + let visible_time = View.timespan_of_width v min_render_width in |
| 245 | + let rec visit ~prev i = |
| 246 | + if i < stop then ( |
| 247 | + let time, e = arr.(i) in |
| 248 | + let next_useful_time = prev +. visible_time in |
| 249 | + if time < next_useful_time then ( |
| 250 | + let i = find_first arr (fun i -> time_of i -. next_useful_time) ~start:(i + 1) - 1 in |
| 251 | + let time, e = arr.(i) in |
| 252 | + fn (i, time, e); |
| 253 | + visit ~prev:time (i + 1) |
| 254 | + ) else ( |
| 255 | + fn (i, time, e); |
| 256 | + visit ~prev:time (i + 1) |
| 257 | + ) |
| 258 | + ) |
| 259 | + in |
| 260 | + visit ~prev:(-.visible_time) start; |
| 261 | + if stop = Array.length arr then |
| 262 | + fn (stop, v.View.layout.duration, []) |
226 | 263 |
|
227 | 264 | let render_gc_events v cr (ring : Layout.Ring.t) layer = |
228 | 265 | let y = y_of_row v ring.y in |
229 | 266 | let h = float ring.height *. Style.line_spacing in |
230 | | - let prev_stack = ref [] in |
231 | | - let event = ref (0.0, []) in |
232 | | - C.set_font_size cr Style.big_text; |
233 | | - ring |> iter_gc_spans v (fun event' -> |
234 | | - let t0, stack = !event in |
235 | | - event := event'; |
236 | | - let t1 = fst event' in |
237 | | - let x0 = View.x_of_time v t0 in |
238 | | - let x1 = View.x_of_time v t1 in |
239 | | - let w = x1 -. x0 in |
240 | | - begin match stack with |
241 | | - | [] -> () |
242 | | - | Suspend op :: p -> |
243 | | - begin match layer with |
| 267 | + if y <= v.height && y +. h >= 0. then( |
| 268 | + let event = ref (0, 0.0, []) in |
| 269 | + C.set_font_size cr Style.big_text; |
| 270 | + ring |> iter_gc_spans v (fun event' -> |
| 271 | + let i, t0, stack = !event in |
| 272 | + let prev_stack = if i = 0 then [] else snd (ring.events.(i - 1)) in |
| 273 | + event := event'; |
| 274 | + let _, t1, _ = event' in |
| 275 | + let x0 = View.x_of_time v t0 in |
| 276 | + let x1 = View.x_of_time v t1 in |
| 277 | + let w = x1 -. x0 in |
| 278 | + begin match stack with |
| 279 | + | [] -> () |
| 280 | + | Suspend op :: p -> |
| 281 | + begin match layer with |
| 282 | + | `Bg -> |
| 283 | + let g = 0.9 in |
| 284 | + C.set_source_rgb cr ~r:g ~g:g ~b:(g /. 2.); |
| 285 | + C.rectangle cr ~x:x0 ~y ~w ~h; |
| 286 | + C.fill cr |
| 287 | + | `Fg -> |
| 288 | + if p == prev_stack then ( |
| 289 | + let clip_area = (w -. 0.2, v.height) in |
| 290 | + C.set_source_rgb cr ~r:0.0 ~g:0.0 ~b:0.0; |
| 291 | + C.paint_text cr ~x:(x0 +. 2.) ~y:(y +. 12.) op |
| 292 | + ~clip_area |
| 293 | + ) |
| 294 | + end |
| 295 | + | Gc op :: p -> |
| 296 | + let g = max 0.1 (0.1 *. float (List.length stack)) in |
| 297 | + match layer with |
244 | 298 | | `Bg -> |
245 | | - let g = 0.9 in |
246 | | - C.set_source_rgb cr ~r:g ~g:g ~b:(g /. 2.); |
| 299 | + C.set_source_rgb cr ~r:1.0 ~g:g ~b:(g /. 2.); |
247 | 300 | C.rectangle cr ~x:x0 ~y ~w ~h; |
248 | 301 | C.fill cr |
249 | 302 | | `Fg -> |
250 | | - if p == !prev_stack then ( |
| 303 | + if p == prev_stack then ( |
251 | 304 | let clip_area = (w -. 0.2, v.height) in |
252 | | - C.set_source_rgb cr ~r:0.0 ~g:0.0 ~b:0.0; |
| 305 | + if g < 0.5 then C.set_source_rgb cr ~r:1.0 ~g:1.0 ~b:1.0 |
| 306 | + else C.set_source_rgb cr ~r:0.0 ~g:0.0 ~b:0.0; |
253 | 307 | C.paint_text cr ~x:(x0 +. 2.) ~y:(y +. 12.) op |
254 | 308 | ~clip_area |
255 | 309 | ) |
256 | | - end |
257 | | - | Gc op :: p -> |
258 | | - let g = max 0.1 (0.1 *. float (List.length stack)) in |
259 | | - match layer with |
260 | | - | `Bg -> |
261 | | - C.set_source_rgb cr ~r:1.0 ~g:g ~b:(g /. 2.); |
262 | | - C.rectangle cr ~x:x0 ~y ~w ~h; |
263 | | - C.fill cr |
264 | | - | `Fg -> |
265 | | - if p == !prev_stack then ( |
266 | | - let clip_area = (w -. 0.2, v.height) in |
267 | | - if g < 0.5 then C.set_source_rgb cr ~r:1.0 ~g:1.0 ~b:1.0 |
268 | | - else C.set_source_rgb cr ~r:0.0 ~g:0.0 ~b:0.0; |
269 | | - C.paint_text cr ~x:(x0 +. 2.) ~y:(y +. 12.) op |
270 | | - ~clip_area |
271 | | - ) |
272 | | - end; |
273 | | - prev_stack := stack |
274 | | - ) |
| 310 | + end |
| 311 | + ) |
| 312 | + ) |
275 | 313 |
|
276 | 314 | let link_domain v cr ~x (fiber : Layout.item) (ring : Layout.Ring.t) = |
277 | 315 | let fiber_y = y_of_row v fiber.y +. Style.fiber_padding_top in |
|
0 commit comments