font_rs/
raster.rs

1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! An antialiased rasterizer for quadratic Beziers
16
17use std::cmp::min;
18
19use accumulate::accumulate;
20use geom::Point;
21
22// TODO: sort out crate structure. Right now we want this when compiling raster as a binary,
23// but need it commented out when compiling showttf
24//mod geom;
25
26pub struct Raster {
27    w: usize,
28    h: usize,
29    a: Vec<f32>,
30}
31
32// TODO: is there a faster way? (investigate whether approx recip is good enough)
33fn recip(x: f32) -> f32 {
34    x.recip()
35}
36
37impl Raster {
38    pub fn new(w: usize, h: usize) -> Raster {
39        Raster {
40            w: w,
41            h: h,
42            a: vec![0.0; w * h + 4],
43        }
44    }
45
46    pub fn draw_line(&mut self, p0: &Point, p1: &Point) {
47        //println!("draw_line {} {}", p0, p1);
48        if p0.y == p1.y {
49            return;
50        }
51        let (dir, p0, p1) = if p0.y < p1.y {
52            (1.0, p0, p1)
53        } else {
54            (-1.0, p1, p0)
55        };
56        let dxdy = (p1.x - p0.x) / (p1.y - p0.y);
57        let mut x = p0.x;
58        let y0 = p0.y as usize; // note: implicit max of 0 because usize (TODO: really true?)
59        if p0.y < 0.0 {
60            x -= p0.y * dxdy;
61        }
62        for y in y0..min(self.h, p1.y.ceil() as usize) {
63            let linestart = y * self.w;
64            let dy = ((y + 1) as f32).min(p1.y) - (y as f32).max(p0.y);
65            let xnext = x + dxdy * dy;
66            let d = dy * dir;
67            let (x0, x1) = if x < xnext { (x, xnext) } else { (xnext, x) };
68            let x0floor = x0.floor();
69            let x0i = x0floor as i32;
70            let x1ceil = x1.ceil();
71            let x1i = x1ceil as i32;
72            if x1i <= x0i + 1 {
73                let xmf = 0.5 * (x + xnext) - x0floor;
74                self.a[linestart + x0i as usize] += d - d * xmf;
75                self.a[linestart + (x0i + 1) as usize] += d * xmf;
76            } else {
77                let s = recip(x1 - x0);
78                let x0f = x0 - x0floor;
79                let a0 = 0.5 * s * (1.0 - x0f) * (1.0 - x0f);
80                let x1f = x1 - x1ceil + 1.0;
81                let am = 0.5 * s * x1f * x1f;
82                self.a[linestart + x0i as usize] += d * a0;
83                if x1i == x0i + 2 {
84                    self.a[linestart + (x0i + 1) as usize] += d * (1.0 - a0 - am);
85                } else {
86                    let a1 = s * (1.5 - x0f);
87                    self.a[linestart + (x0i + 1) as usize] += d * (a1 - a0);
88                    for xi in x0i + 2..x1i - 1 {
89                        self.a[linestart + xi as usize] += d * s;
90                    }
91                    let a2 = a1 + (x1i - x0i - 3) as f32 * s;
92                    self.a[linestart + (x1i - 1) as usize] += d * (1.0 - a2 - am);
93                }
94                self.a[linestart + x1i as usize] += d * am;
95            }
96            x = xnext;
97        }
98    }
99
100    pub fn draw_quad(&mut self, p0: &Point, p1: &Point, p2: &Point) {
101        //println!("draw_quad {} {} {}", p0, p1, p2);
102        let devx = p0.x - 2.0 * p1.x + p2.x;
103        let devy = p0.y - 2.0 * p1.y + p2.y;
104        let devsq = devx * devx + devy * devy;
105        if devsq < 0.333 {
106            self.draw_line(p0, p2);
107            return;
108        }
109        let tol = 3.0;
110        let n = 1 + (tol * (devx * devx + devy * devy)).sqrt().sqrt().floor() as usize;
111        //println!("n = {}", n);
112        let mut p = *p0;
113        let nrecip = recip(n as f32);
114        let mut t = 0.0;
115        for _i in 0..n - 1 {
116            t += nrecip;
117            let pn = Point::lerp(t, &Point::lerp(t, p0, p1), &Point::lerp(t, p1, p2));
118            self.draw_line(&p, &pn);
119            p = pn;
120        }
121        self.draw_line(&p, p2);
122    }
123
124    /*
125    fn get_bitmap_fancy(&self) -> Vec<u8> {
126        let mut acc = 0.0;
127        // This would translate really well to SIMD
128        self.a[0..self.w * self.h].iter().map(|&a| {
129            acc += a;
130            (255.0 * acc.abs().min(1.0)) as u8
131            //(255.5 * (0.5 + 0.4 * acc)) as u8
132        }).collect()
133    }
134*/
135
136    pub fn get_bitmap(&self) -> Vec<u8> {
137        accumulate(&self.a[0..self.w * self.h])
138    }
139}