Bug 1318440 - Vendor in the dwrote package. r=bustage
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 17 Nov 2016 18:32:35 -0500
changeset 459780 5dd89a707d7271d378930ebe23cbfdaa0c7110ca
parent 459779 1acc749a9a21755aeb6ae59cd7fd5333578b2cb5
child 459781 73f79bd8f8a38da87fa7b8acc3f81adfb49f3889
push id41343
push userkgupta@mozilla.com
push dateThu, 12 Jan 2017 20:13:44 +0000
reviewersbustage
bugs1318440
milestone53.0a1
Bug 1318440 - Vendor in the dwrote package. r=bustage MozReview-Commit-ID: DlKRgGac1EQ
third_party/rust/dwrite-sys/i686/libdwrite.a
third_party/rust/dwrite-sys/x86_64/libdwrite.a
third_party/rust/dwrote/.cargo-checksum.json
third_party/rust/dwrote/.cargo-ok
third_party/rust/dwrote/.gitignore
third_party/rust/dwrote/Cargo.toml
third_party/rust/dwrote/README.md
third_party/rust/dwrote/build.rs
third_party/rust/dwrote/src/bitmap_render_target.rs
third_party/rust/dwrote/src/comptr.rs
third_party/rust/dwrote/src/font.rs
third_party/rust/dwrote/src/font_collection.rs
third_party/rust/dwrote/src/font_face.rs
third_party/rust/dwrote/src/font_family.rs
third_party/rust/dwrote/src/font_file.rs
third_party/rust/dwrote/src/gdi_interop.rs
third_party/rust/dwrote/src/helpers.rs
third_party/rust/dwrote/src/lib.rs
third_party/rust/dwrote/src/rendering_params.rs
third_party/rust/dwrote/src/test.rs
third_party/rust/dwrote/src/types.rs
toolkit/library/gtest/rust/Cargo.lock
toolkit/library/rust/Cargo.lock
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..524193c476605efacb6c0c4512834888de980195
GIT binary patch
literal 2256
zc$~$R&rjPh6vtoEv}G9+9MHsJn}W36rjVv-T1{v|+r)_*2X+fCNtcK~QS1G>@h9*n
zq5WZFes)}(I;L#Wge5yK?|tKEKY!%x?2*}N{@&g7>a7>`hr?(v3VWUxaF05&co<jK
zi3<P@>%Rb69{@V**ps9z#{Ce-^!u!!SwfQHf}CfNBzZ<sJq*dGW3)cbGD5Qha!RMO
zpZmR#eNdcVCZ;H)Q<_tMy1Q!Sy&#BVw&=kqSgice>HxNF3t)p=ZOf<G4+{4;4}udv
zC6uht?L%<mkLU9hGPpurffK%tqz_B#SPk<D-9Xi?nRP?yTgTp@leVa@pOz(nKPk$r
z^8daC_+m}SSyum6trJe$TAG_{lp5J4jZ&YMNu$)p;Tp%J;dN=>ui-W6aLrRaS(QU-
zY<R^+GtbCh{ulhkgTBUJ%=Ww~GCwwdq4aHm;BUJ+j}|oZXUx0Avq@))A+KFNZg30h
z^Nd>$p)==aBN{(xn9%&|#hLJMJ|2T$UR^=(R;AW7(cPLgra^u$pEkE%Dzn&tc$;ro
zBgih2JP)u5oL7<@4Hc5RJo^>fyDL_wk-WzGTNeLp-PQa*lDxS2uuc(6HdgY2;U*oi
zVA-sz-OPI|_^nwNOWku^x5k2ZbNdFL*VlD_!~YG$`C>kCPdowSAF6lN(pc8X)j6%*
mhYmCoXQYzvvkS{qS|F)>QF+=6&pTzmHXO0>-+uZ=y4^o4gBjZZ
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..604d57a1c04028e59f69e07fa7f53a8348e17f12
GIT binary patch
literal 2250
zc$~$R&rjPh6vtosi_&#shYE3+P$rGr6x=BFI%%3JZ9-@#Zab!ixFl=&q1F@ZGVL^R
z<j>iWziiBQ;^M}3TP|S9&eMC}_}R~&IB!0Z=}G#jweK&sZWM+g`Vd8Z-$&A;k38PR
zg*9veK#ljm0M!9NqbYhEPqJeii7~mFW{k!p&d$jhg*c@oF{AM1n=n34DPi=0oUn`O
zPl)5}>@v1R5;{I*!NvZn^>z`$m@l>0@6Xqp{Aqw_z6Y=+tvUpZUNczUd^j2g31MV~
zZU9Gj!SQUiLI%HuE)x^Jjg+q`is_Z-LrT}vb#1rqz4Enr?^tx@wd6GplF0-h7-bV$
z`2XDloO&ZNri*&LUSj%cDTmZ(wW_!@TAivcjaH+Y)HGchS)clHjjT;WYF?PhiX2K)
zfn7ejX%-x&kKhpZLW4uh_x!5J{LCDN%GZIM!=2(hs$l2Po);NhyL7HtTjmtwmb65D
zUP@~nI#YQzd6Op%BbNR+ALpKWKF`w=EUTLn+$q$CCVE)2!8EA%)w3e4*V-%<z<hMw
zvCBE0A<=S}S8^O-jpGfO`-bnlRjjSdvG^L_@%YetsJIVkO^(r;9Gmx_s8Ym}eb@4W
z<38>4AhYWh?&kpy{<7<^(rxp8XprFF-S3I#?X7(Wwm)5d%1uxwzX^(jM#(aWHu*Ja
oUAPr%VCT-srrhral-cw^vAI)t>T}QhijkhLj$OO|{4Tct1JUyrBme*a
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/.cargo-checksum.json
@@ -0,0 +1,1 @@
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"172610b244a5ee8a8e2f1f045058b8abf9291d84bb76bf8779d2fd420419c2d6","Cargo.toml":"e4fb60c9e095cc4eba483b31084b2ed2080d46c7669260b682df2fa2db0b3fcb","README.md":"d69d75705e2582721cbfb2d3b4b2af052c71679057a0b2ac53a22c03f1755bba","build.rs":"fea382a72243440bcfc334229684fecd2e0021f740dd95d2e2df267744cce402","src/bitmap_render_target.rs":"ff1c34aad7e3930c0a1f5778f01056a2bc7a41c8edce892b5672d92cdba78c89","src/comptr.rs":"fdea6d9d860fc6820af26a57177a1c70a319dde86957249b51cf86f11feef1a2","src/font.rs":"b7e48990e2be1c99680673e10334f3e8563f575b4901204a6ec902aa5be12be6","src/font_collection.rs":"969fa3abf141dc3504774886f4783fda4a74cd5a198c643f8a77fc1af4e75258","src/font_face.rs":"cfce3df6c28e070f6f37bc5ca61587d6d8cd8092e716327a625e1eb72a69446b","src/font_family.rs":"403da9f8f9903cbe7f9f79636497b273f9885e200f53af99f9d4e483f11d6889","src/font_file.rs":"36313b4c6f1e29797f2da79e9ade2a5d15bcd8867707fc9746cdb98da973a550","src/gdi_interop.rs":"627a39c72d162308826ac1090972179d39f9962c8e7f29925983744a96862d84","src/helpers.rs":"5d6f164468234ca8806dc1cea117b42dbfae80cc4c9ae965cb0556efdb364682","src/lib.rs":"6ed2fcf2782d940a22da6f7fce9da08f718dd7d68741f9a4dade4d6bf2a465c2","src/rendering_params.rs":"9b132aef922f1ff3df06a1b126eccb6a397e81a04625afdb7b72dc2f968c92cd","src/test.rs":"3bc96cc2aeef45eb0a8f12439147a69d0d001af1d8800528e829aed874ea79be","src/types.rs":"ef82336fbb30d272b201f22b23719399089301ea34c60f63858b53552d09ac61"},"package":"65c6ec960350000aaeb2ae745e63d01f225a5485d537c8e265a12a781ed1fdf0"}
\ No newline at end of file
copy from third_party/rust/dwrite-sys/x86_64/libdwrite.a
copy to third_party/rust/dwrote/.cargo-ok
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/.gitignore
@@ -0,0 +1,5 @@
+target
+Cargo.lock
+*~
+#~#
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/Cargo.toml
@@ -0,0 +1,31 @@
+[package]
+name = "dwrote"
+description = "Lightweight binding to DirectWrite."
+repository = "https://github.com/vvuk/dwrote-rs"
+license = "MPL-2.0"
+version = "0.1.0"
+authors = ["Vladimir Vukicevic <vladimir@pobox.com>"]
+build = "build.rs"
+
+[lib]
+name = "dwrote"
+
+[features]
+default = ["codegen"]
+nightly = ["serde/unstable"]
+codegen = ["serde_codegen", "serde_codegen/with-syntex"]
+
+[dependencies]
+libc = "0.2"
+lazy_static = "0.2"
+winapi = "0.2"
+kernel32-sys = "0.2"
+gdi32-sys = "0.2"
+dwrite-sys = "0.2"
+serde = "0.8"
+serde_derive = {version = "0.8", optional = true}
+
+[build-dependencies.serde_codegen]
+version = "0.8"
+default_features = false
+optional = true
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/README.md
@@ -0,0 +1,12 @@
+# dwrote
+A thin wrapper around Windows DirectWrite for Rust
+
+Dwrote provides access to pieces of DirectWrite needed by WebRender
+and Servo.  It can be easily extended to other parts of DirectWrite,
+but full mapping of the DirectWrite API is not a goal (pull requests
+accepted, of course).
+
+There are a few additional helper functions on individual types that
+don't exist in DirectWrite, and a few have had their signatures changed,
+but for the most part this library attempts to replicate the DirectWrite
+API.
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/build.rs
@@ -0,0 +1,46 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#[cfg(all(feature = "serde_codegen", not(feature = "serde_derive")))]
+mod inner {
+    extern crate serde_codegen;
+
+    use std::env;
+    use std::path::Path;
+
+    pub fn main() {
+        let out_dir = env::var_os("OUT_DIR").unwrap();
+
+        let src = Path::new("src/types.rs");
+        let dst = Path::new(&out_dir).join("types.rs");
+
+        serde_codegen::expand(&src, &dst).unwrap();
+        println!("cargo:rerun-if-changed=src/types.rs");
+    }
+}
+
+#[cfg(all(feature = "serde_derive", not(feature = "serde_codegen")))]
+mod inner {
+    pub fn main() {}
+}
+
+#[cfg(all(feature = "serde_codegen", feature = "serde_derive"))]
+mod inner {
+    pub fn main() {
+        panic!("serde_codegen and serde_derive are both used. \
+               You probably forgot --no-default-features.")
+    }
+}
+
+#[cfg(not(any(feature = "serde_codegen", feature = "serde_derive")))]
+mod inner {
+    pub fn main() {
+        panic!("Neither serde_codegen nor serde_derive are used. "
+               "You probably want --features serde_derive --no-default-features.")
+    }
+}
+
+fn main() {
+    inner::main();
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/bitmap_render_target.rs
@@ -0,0 +1,121 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::slice;
+use std::ptr;
+use std::cell::UnsafeCell;
+use std::mem::{zeroed, size_of};
+
+use comptr::ComPtr;
+use winapi;
+use gdi32;
+use super::{FontFace, RenderingParams};
+
+#[derive(Debug)]
+pub struct BitmapRenderTarget {
+    native: UnsafeCell<ComPtr<winapi::IDWriteBitmapRenderTarget>>,
+}
+
+impl BitmapRenderTarget {
+    pub fn take(native: ComPtr<winapi::IDWriteBitmapRenderTarget>) -> BitmapRenderTarget {
+        BitmapRenderTarget {
+            native: UnsafeCell::new(native),
+        }
+    }
+
+    pub unsafe fn as_ptr(&self) -> *mut winapi::IDWriteBitmapRenderTarget {
+        (*self.native.get()).as_ptr()
+    }
+
+    // A dip is 1/96th of an inch, so this value is the number of pixels per inch divided by 96.
+    pub fn set_pixels_per_dip(&self, ppd: f32) {
+        unsafe {
+            (*self.native.get()).SetPixelsPerDip(ppd);
+        }
+    }
+    
+    pub fn get_memory_dc(&self) -> winapi::HDC {
+        unsafe {
+            (*self.native.get()).GetMemoryDC()
+        }
+    }
+
+    pub fn draw_glyph_run(&self,
+                          baseline_origin_x: f32,
+                          baseline_origin_y: f32,
+                          measuring_mode: winapi::DWRITE_MEASURING_MODE,
+                          font_face: &FontFace,
+                          em_size: f32,
+                          glyph_indices: &[u16],
+                          glyph_advances: &[f32],
+                          glyph_offsets: &[winapi::DWRITE_GLYPH_OFFSET],
+                          rendering_params: &RenderingParams,
+                          color: &(f32, f32, f32))
+    {
+        unsafe {
+            assert!(glyph_indices.len() == glyph_advances.len());
+            assert!(glyph_indices.len() == glyph_offsets.len());
+            
+            let r = (color.0 * 255.0) as u8;
+            let g = (color.1 * 255.0) as u8;
+            let b = (color.2 * 255.0) as u8;
+
+            let mut glyph_run: winapi::DWRITE_GLYPH_RUN = zeroed();
+            glyph_run.fontFace = font_face.as_ptr();
+            glyph_run.fontEmSize = em_size;
+            glyph_run.glyphCount = glyph_indices.len() as u32;
+            glyph_run.glyphIndices = glyph_indices.as_ptr();
+            glyph_run.glyphAdvances = glyph_advances.as_ptr();
+            glyph_run.glyphOffsets = glyph_offsets.as_ptr();
+            glyph_run.isSideways = 0;
+            glyph_run.bidiLevel = 0;
+
+            (*self.native.get()).DrawGlyphRun(baseline_origin_x,
+                                              baseline_origin_y,
+                                              measuring_mode,
+                                              &glyph_run,
+                                              rendering_params.as_ptr(),
+                                              winapi::RGB(r,g,b),
+                                              ptr::null_mut());
+        }
+    }
+
+    // This function expects to have glyphs rendered in WHITE,
+    // and pulls out a u8 vector of width*height*4 size with
+    // the coverage value (we pull out R) broadcast to the alpha
+    // channel, with the color white.  That is, it performs:
+    // RGBX -> xxxR, where xxx = 0xff
+    pub fn get_opaque_values_as_mask(&self) -> Vec<u8> {
+        // Now grossness to pull out the pixels
+        unsafe {
+            let memory_dc = self.get_memory_dc();
+            let mut bitmap: winapi::BITMAP = zeroed();
+            let ret = gdi32::GetObjectW(gdi32::GetCurrentObject(memory_dc, winapi::OBJ_BITMAP),
+                                        size_of::<winapi::BITMAP>() as i32,
+                                        &mut bitmap as *mut _ as *mut winapi::c_void);
+            assert!(ret == size_of::<winapi::BITMAP>() as i32);
+            assert!(bitmap.bmBitsPixel == 32);
+
+            let width = bitmap.bmWidth as usize;
+            let stride = bitmap.bmWidthBytes as usize;
+            let height = bitmap.bmHeight as usize;
+
+            let mut out_bytes: Vec<u8> = vec![0; width * height * 4];
+            let mut out_u32 = slice::from_raw_parts_mut(out_bytes.as_mut_ptr() as *mut u32,
+                                                        width * height);
+
+            for row in 0..height {
+                let in_offset = (row * stride) as isize;
+                let in_u32 = slice::from_raw_parts(bitmap.bmBits.offset(in_offset) as *const u32,
+                                                   width);
+                for col in 0..width {
+                    let r = in_u32[col] & 0xff;
+                    out_u32[width*row + col] = (r << 24) | (0x00ffffffu32);
+                }
+            }
+
+            out_bytes
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/comptr.rs
@@ -0,0 +1,92 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::ops::{Deref, DerefMut};
+use std::ptr;
+use winapi::{IUnknown, REFIID};
+
+#[derive(Debug)]
+pub struct ComPtr<T> {
+    ptr: *mut T,
+}
+
+impl<T> ComPtr<T> {
+    pub fn new() -> Self {
+        ComPtr { ptr: ptr::null_mut() }
+    }
+
+    pub fn already_addrefed(ptr: *mut T) -> Self {
+        ComPtr { ptr: ptr }
+    }
+
+    pub fn getter_addrefs<Q>(&mut self) -> *mut *mut Q {
+        self.release();
+        return &mut self.ptr as *mut *mut _ as *mut *mut Q;
+    }
+
+    pub fn as_ptr(&self) -> *mut T {
+        self.ptr
+    }
+
+    pub fn query_interface<Q>(&self, _: REFIID) -> Option<ComPtr<Q>> {
+        panic!("Here's where the code goes when you need it");
+    }
+
+    pub fn addref(&self) {
+        unsafe {
+            assert!(!self.ptr.is_null());
+            (*(self.ptr as *mut IUnknown)).AddRef();
+        }
+    }
+
+    pub fn release(&self) {
+        unsafe {
+            if !self.ptr.is_null() {
+                (*(self.ptr as *mut IUnknown)).Release();
+            }
+        }
+    }
+
+    pub fn forget(&mut self) -> *mut T {
+        let ptr = self.ptr;
+        self.ptr = ptr::null_mut();
+        ptr
+    }
+}
+
+impl<T> Clone for ComPtr<T> {
+    fn clone(&self) -> Self {
+        if !self.ptr.is_null() {
+            self.addref();
+        }
+        ComPtr { ptr: self.ptr }
+    }
+}
+
+impl<T> Deref for ComPtr<T> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        assert!(!self.ptr.is_null());
+        unsafe { &mut *self.ptr }
+    }
+}
+
+impl<T> DerefMut for ComPtr<T> {
+    fn deref_mut(&mut self) -> &mut T {
+        assert!(!self.ptr.is_null());
+        unsafe { &mut *self.ptr }
+    }
+}
+
+impl<T> PartialEq for ComPtr<T> {
+    fn eq(&self, other: &ComPtr<T>) -> bool {
+        self.ptr == other.ptr
+    }
+}
+
+impl<T> Drop for ComPtr<T> {
+    fn drop(&mut self) {
+        self.release();
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/font.rs
@@ -0,0 +1,87 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::cell::UnsafeCell;
+
+use comptr::ComPtr;
+use winapi;
+use std::mem;
+
+use super::*;
+use helpers::*;
+
+#[derive(Debug)]
+pub struct Font {
+    native: UnsafeCell<ComPtr<winapi::IDWriteFont>>,
+}
+
+impl Font {
+    pub fn take(native: ComPtr<winapi::IDWriteFont>) -> Font {
+        Font {
+            native: UnsafeCell::new(native),
+        }
+    }
+
+    pub unsafe fn as_ptr(&self) -> *mut winapi::IDWriteFont {
+        (*self.native.get()).as_ptr()
+    }
+
+    pub fn to_descriptor(&self) -> FontDescriptor {
+        FontDescriptor {
+            family_name: self.family_name(),
+            stretch: self.stretch(),
+            style: self.style(),
+            weight: self.weight(),
+        }
+    }
+
+    pub fn stretch(&self) -> FontStretch {
+        unsafe {
+            mem::transmute((*self.native.get()).GetStretch().0)
+        }
+    }
+
+    pub fn style(&self) -> FontStyle {
+        unsafe {
+            mem::transmute((*self.native.get()).GetStyle().0)
+        }
+    }
+
+    pub fn weight(&self) -> FontWeight {
+        unsafe {
+            mem::transmute((*self.native.get()).GetWeight().0)
+        }
+    }
+
+    pub fn family_name(&self) -> String {
+        unsafe {
+            let mut family: ComPtr<winapi::IDWriteFontFamily> = ComPtr::new();
+            let hr = (*self.native.get()).GetFontFamily(family.getter_addrefs());
+            assert!(hr == 0);
+
+            FontFamily::take(family).name()
+        }
+    }
+
+    pub fn face_name(&self) -> String {
+        unsafe {
+            let mut names: ComPtr<winapi::IDWriteLocalizedStrings> = ComPtr::new();
+            let hr = (*self.native.get()).GetFaceNames(names.getter_addrefs());
+            assert!(hr == 0);
+
+            get_locale_string(&mut names)
+        }
+    }
+
+    pub fn create_font_face(&self) -> FontFace {
+        // FIXME create_font_face should cache the FontFace and return it,
+        // there's a 1:1 relationship
+        unsafe {
+            let mut face: ComPtr<winapi::IDWriteFontFace> = ComPtr::new();
+            let hr = (*self.native.get()).CreateFontFace(face.getter_addrefs());
+            assert!(hr == 0);
+            FontFace::take(face)
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/font_collection.rs
@@ -0,0 +1,135 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use comptr::ComPtr;
+use winapi;
+use winapi::FALSE;
+use std::cell::UnsafeCell;
+
+use super::{DWriteFactory, FontFamily, Font, FontFace, FontDescriptor};
+use helpers::*;
+
+#[derive(Debug)]
+pub struct FontCollectionFamilyIterator {
+    collection: ComPtr<winapi::IDWriteFontCollection>,
+    curr: u32,
+    count: u32,
+}
+
+impl Iterator for FontCollectionFamilyIterator {
+    type Item = FontFamily;
+    fn next(&mut self) -> Option<FontFamily> {
+        if self.curr == self.count {
+            return None;
+        }
+
+        unsafe {
+            let mut family: ComPtr<winapi::IDWriteFontFamily> = ComPtr::new();
+            let hr = self.collection.GetFontFamily(self.curr, family.getter_addrefs());
+            assert!(hr == 0);
+            self.curr += 1;
+            Some(FontFamily::take(family))
+        }
+    }
+}
+
+pub struct FontCollection {
+    native: UnsafeCell<ComPtr<winapi::IDWriteFontCollection>>,
+}
+
+impl FontCollection {
+    pub fn system() -> FontCollection {
+        unsafe {
+            let mut native: ComPtr<winapi::IDWriteFontCollection> = ComPtr::new();
+            let hr = (*DWriteFactory()).GetSystemFontCollection(native.getter_addrefs(), FALSE);
+            assert!(hr == 0);
+
+            FontCollection {
+                native: UnsafeCell::new(native)
+            }
+        }
+    }
+
+    pub fn take(native: ComPtr<winapi::IDWriteFontCollection>) -> FontCollection {
+        FontCollection {
+            native: UnsafeCell::new(native)
+        }
+    }
+
+    pub unsafe fn as_ptr(&self) -> *mut winapi::IDWriteFontCollection {
+        (*self.native.get()).as_ptr()
+    }
+
+    
+    pub fn families_iter(&self) -> FontCollectionFamilyIterator {
+        unsafe {
+            FontCollectionFamilyIterator {
+                collection: (*self.native.get()).clone(),
+                curr: 0,
+                count: (*self.native.get()).GetFontFamilyCount(),
+            }
+        }
+    }
+
+    pub fn get_font_family_count(&self) -> u32 {
+        unsafe {
+            (*self.native.get()).GetFontFamilyCount()
+        }
+    }
+
+    pub fn get_font_family(&self, index: u32) -> FontFamily {
+        unsafe {
+            let mut family: ComPtr<winapi::IDWriteFontFamily> = ComPtr::new();
+            let hr = (*self.native.get()).GetFontFamily(index, family.getter_addrefs());
+            assert!(hr == 0);
+            FontFamily::take(family)
+        }
+    }
+
+    // Find a font matching the given font descriptor in this
+    // font collection.  
+    pub fn get_font_from_descriptor(&self, desc: &FontDescriptor) -> Option<Font> {
+        if let Some(family) = self.get_font_family_by_name(&desc.family_name) {
+            let font = family.get_first_matching_font(desc.weight, desc.stretch, desc.style);
+            // Exact matches only here
+            if font.weight() == desc.weight &&
+                font.stretch() == desc.stretch &&
+                font.style() == desc.style
+            {
+                return Some(font);
+            }
+        }
+
+        None
+    }
+
+    pub fn get_font_from_face(&self, face: &FontFace) -> Option<Font> {
+        unsafe {
+            let mut font: ComPtr<winapi::IDWriteFont> = ComPtr::new();
+            let hr = (*self.native.get()).GetFontFromFontFace(face.as_ptr(), font.getter_addrefs());
+            if hr != 0 {
+                return None;
+            }
+            Some(Font::take(font))
+        }
+    }
+
+    pub fn get_font_family_by_name(&self, family_name: &str) -> Option<FontFamily> {
+        unsafe {
+            let mut index: u32 = 0;
+            let mut exists: winapi::BOOL = winapi::FALSE;
+            let hr = (*self.native.get()).FindFamilyName(family_name.to_wide_null().as_ptr(), &mut index, &mut exists);
+            assert!(hr == 0);
+            if exists == winapi::FALSE {
+                return None;
+            }
+
+            let mut family: ComPtr<winapi::IDWriteFontFamily> = ComPtr::new();
+            let hr = (*self.native.get()).GetFontFamily(index, family.getter_addrefs());
+            assert!(hr == 0);
+
+            Some(FontFamily::take(family))
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/font_face.rs
@@ -0,0 +1,119 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::slice;
+use std::ptr;
+use std::cell::UnsafeCell;
+use std::mem::zeroed;
+
+use comptr::ComPtr;
+use super::{FontMetrics, FontFile};
+
+use winapi;
+
+#[derive(Debug)]
+pub struct FontFace {
+    native: UnsafeCell<ComPtr<winapi::IDWriteFontFace>>,
+    metrics: FontMetrics,
+}
+
+impl FontFace {
+    pub fn take(native: ComPtr<winapi::IDWriteFontFace>) -> FontFace {
+        unsafe {
+            let mut metrics: FontMetrics = zeroed();
+            let cell = UnsafeCell::new(native);
+            (*cell.get()).GetMetrics(&mut metrics);
+            FontFace {
+                native: cell,
+                metrics: metrics,
+            }
+        }
+    }
+
+    pub unsafe fn as_ptr(&self) -> *mut winapi::IDWriteFontFace {
+        (*self.native.get()).as_ptr()
+    }
+
+    pub fn get_files(&self) -> Vec<FontFile> {
+        unsafe {
+            let mut number_of_files: u32 = 0;
+            let hr = (*self.native.get()).GetFiles(&mut number_of_files, ptr::null_mut());
+            assert!(hr == 0);
+
+            let mut file_ptrs: Vec<*mut winapi::IDWriteFontFile> =
+                vec![ptr::null_mut(); number_of_files as usize];
+            let hr = (*self.native.get()).GetFiles(&mut number_of_files, file_ptrs.as_mut_ptr());
+            assert!(hr == 0);
+
+            file_ptrs.iter().map(|p| FontFile::take(ComPtr::already_addrefed(*p))).collect()
+        }
+    }
+
+    pub fn get_glyph_count(&self) -> u16 {
+        unsafe {
+            (*self.native.get()).GetGlyphCount()
+        }
+    }
+
+    pub fn metrics(&self) -> &FontMetrics {
+        &self.metrics
+    }
+
+    pub fn get_metrics(&self) -> FontMetrics {
+        unsafe {
+            let mut metrics: winapi::DWRITE_FONT_METRICS = zeroed();
+            (*self.native.get()).GetMetrics(&mut metrics);
+            metrics
+        }
+    }
+
+    pub fn get_glyph_indices(&self, code_points: &[u32]) -> Vec<u16> {
+        unsafe {
+            let mut glyph_indices: Vec<u16> = vec![0; code_points.len()];
+            let hr = (*self.native.get()).GetGlyphIndices(code_points.as_ptr(),
+                                                          code_points.len() as u32,
+                                                          glyph_indices.as_mut_ptr());
+            assert!(hr == 0);
+            glyph_indices
+        }
+    }
+
+    pub fn get_design_glyph_metrics(&self, glyph_indices: &[u16], is_sideways: bool) -> Vec<winapi::DWRITE_GLYPH_METRICS> {
+        unsafe {
+            let mut metrics: Vec<winapi::DWRITE_GLYPH_METRICS> = vec![zeroed(); glyph_indices.len()];
+            let hr = (*self.native.get()).GetDesignGlyphMetrics(glyph_indices.as_ptr(),
+                                                                glyph_indices.len() as u32,
+                                                                metrics.as_mut_ptr(),
+                                                                is_sideways as winapi::BOOL);
+            assert!(hr == 0);
+            metrics
+        }
+    }
+
+    pub fn get_font_table(&self, opentype_table_tag: u32) -> Option<Vec<u8>> {
+        unsafe {
+            let mut table_data_ptr: *const u8 = ptr::null_mut();
+            let mut table_size: u32 = 0;
+            let mut table_context: *mut winapi::c_void = ptr::null_mut();
+            let mut exists: winapi::BOOL = winapi::FALSE;
+
+            let hr = (*self.native.get()).TryGetFontTable(opentype_table_tag,
+                                                          &mut table_data_ptr as *mut *const _ as *mut *const winapi::c_void,
+                                                          &mut table_size,
+                                                          &mut table_context,
+                                                          &mut exists);
+            assert!(hr == 0);
+
+            if exists == winapi::FALSE {
+                return None;
+            }
+
+            let table_bytes = slice::from_raw_parts(table_data_ptr, table_size as usize).to_vec();
+
+            (*self.native.get()).ReleaseFontTable(table_context);
+
+            Some(table_bytes)
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/font_family.rs
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::cell::UnsafeCell;
+
+use comptr::ComPtr;
+use winapi;
+
+use super::*;
+use helpers::*;
+
+#[derive(Debug)]
+pub struct FontFamily {
+    native: UnsafeCell<ComPtr<winapi::IDWriteFontFamily>>,
+}
+
+impl FontFamily {
+    pub fn take(native: ComPtr<winapi::IDWriteFontFamily>) -> FontFamily {
+        FontFamily {
+            native: UnsafeCell::new(native)
+        }
+    }
+
+    pub unsafe fn as_ptr(&self) -> *mut winapi::IDWriteFontFamily {
+        (*self.native.get()).as_ptr()
+    }
+
+    pub fn name(&self) -> String {
+        unsafe {
+            let mut family_names: ComPtr<winapi::IDWriteLocalizedStrings> = ComPtr::new();
+            let hr = (*self.native.get()).GetFamilyNames(family_names.getter_addrefs());
+            assert!(hr == 0);
+
+            get_locale_string(&mut family_names)
+        }
+    }
+
+    pub fn get_first_matching_font(&self,
+                                   weight: FontWeight,
+                                   stretch: FontStretch,
+                                   style: FontStyle)
+        -> Font
+    {
+        unsafe {
+            let mut font: ComPtr<winapi::IDWriteFont> = ComPtr::new();
+            let hr = (*self.native.get()).GetFirstMatchingFont(weight.t(), stretch.t(), style.t(), font.getter_addrefs());
+            assert!(hr == 0);
+            Font::take(font)
+        }
+    }
+
+    pub fn get_font_collection(&self) -> FontCollection {
+        unsafe {
+            let mut collection: ComPtr<winapi::IDWriteFontCollection> = ComPtr::new();
+            let hr = (*self.native.get()).GetFontCollection(collection.getter_addrefs());
+            assert!(hr == 0);
+            FontCollection::take(collection)
+        }
+    }
+
+    pub fn get_font_count(&self) -> u32 {
+        unsafe {
+            (*self.native.get()).GetFontCount()
+        }
+    }
+
+    pub fn get_font(&self, index: u32) -> Font {
+        unsafe {
+            let mut font: ComPtr<winapi::IDWriteFont> = ComPtr::new();
+            let hr = (*self.native.get()).GetFont(index, font.getter_addrefs());
+            assert!(hr == 0);
+            Font::take(font)
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/font_file.rs
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::slice;
+use std::ptr;
+use std::cell::UnsafeCell;
+
+use comptr::ComPtr;
+
+use winapi;
+
+#[derive(Debug)]
+pub struct FontFile {
+    native: UnsafeCell<ComPtr<winapi::IDWriteFontFile>>,
+}
+
+impl FontFile {
+    pub fn take(native: ComPtr<winapi::IDWriteFontFile>) -> FontFile {
+        FontFile {
+            native: UnsafeCell::new(native),
+        }
+    }
+
+    pub unsafe fn as_ptr(&self) -> *mut winapi::IDWriteFontFile {
+        (*self.native.get()).as_ptr()
+    }
+
+    // This is a helper to read the contents of this FontFile,
+    // without requiring callers to deal with loaders, keys,
+    // or streams.
+    pub fn get_font_file_bytes(&self) -> Vec<u8> {
+        unsafe {
+            let mut ref_key: *const winapi::c_void = ptr::null();
+            let mut ref_key_size: u32 = 0;
+            let hr = (*self.native.get()).GetReferenceKey(&mut ref_key, &mut ref_key_size);
+            assert!(hr == 0);
+
+            let mut loader: ComPtr<winapi::IDWriteFontFileLoader> = ComPtr::new();
+            let hr = (*self.native.get()).GetLoader(loader.getter_addrefs());
+            assert!(hr == 0);
+
+            let mut stream: ComPtr<winapi::IDWriteFontFileStream> = ComPtr::new();
+            let hr = loader.CreateStreamFromKey(ref_key, ref_key_size, stream.getter_addrefs());
+            assert!(hr == 0);
+
+            let mut file_size: u64 = 0;
+            let hr = stream.GetFileSize(&mut file_size);
+            assert!(hr == 0);
+
+            let mut fragment_start: *const winapi::c_void = ptr::null();
+            let mut fragment_context: *mut winapi::c_void = ptr::null_mut();
+            let hr = stream.ReadFileFragment(&mut fragment_start, 0, file_size, &mut fragment_context);
+            assert!(hr == 0);
+
+            let in_ptr = slice::from_raw_parts(fragment_start as *const u8, file_size as usize);
+            let bytes = in_ptr.to_vec();
+
+            stream.ReleaseFileFragment(fragment_context);
+
+            bytes
+        }
+    }
+
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/gdi_interop.rs
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::ptr;
+use std::cell::UnsafeCell;
+
+use comptr::ComPtr;
+use winapi;
+use super::{DWriteFactory, BitmapRenderTarget};
+
+#[derive(Debug)]
+pub struct GdiInterop {
+    native: UnsafeCell<ComPtr<winapi::IDWriteGdiInterop>>,
+}
+
+impl GdiInterop {
+    pub fn create() -> GdiInterop {
+        unsafe {
+            let mut native: ComPtr<winapi::IDWriteGdiInterop> = ComPtr::new();
+            let hr = (*DWriteFactory()).GetGdiInterop(native.getter_addrefs());
+            assert!(hr == 0);
+            GdiInterop::take(native)
+        }
+    }
+
+    pub fn take(native: ComPtr<winapi::IDWriteGdiInterop>) -> GdiInterop {
+        GdiInterop {
+            native: UnsafeCell::new(native),
+        }
+    }
+
+    pub fn create_bitmap_render_target(&self, width: u32, height: u32) -> BitmapRenderTarget {
+        unsafe {
+            let mut native: ComPtr<winapi::IDWriteBitmapRenderTarget> = ComPtr::new();
+            let hr = (*self.native.get()).CreateBitmapRenderTarget(ptr::null_mut(),
+                                                                   width, height,
+                                                                   native.getter_addrefs());
+            assert!(hr == 0);
+            BitmapRenderTarget::take(native)
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/helpers.rs
@@ -0,0 +1,67 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use winapi::IDWriteLocalizedStrings;
+use winapi::wchar_t;
+use comptr::ComPtr;
+use winapi::winerror::S_OK;
+use winapi::minwindef::{BOOL, FALSE};
+use kernel32;
+use std::ffi::{OsStr};
+use std::os::windows::ffi::{OsStrExt};
+
+lazy_static! {
+    static ref SYSTEM_LOCALE: Vec<wchar_t> = {
+        unsafe {
+            let mut locale: Vec<wchar_t> = vec![0; 85];
+            kernel32::GetUserDefaultLocaleName(locale.as_mut_ptr(), locale.len() as i32 - 1);
+            locale
+        }
+    };
+    static ref EN_US_LOCALE: Vec<wchar_t> = {
+        OsStr::new("en-us").encode_wide().collect()
+    };
+}
+
+pub fn get_locale_string(strings: &mut ComPtr<IDWriteLocalizedStrings>) -> String {
+    unsafe {
+        let mut index: u32 = 0;
+        let mut exists: BOOL = FALSE;
+        let hr = strings.FindLocaleName((*SYSTEM_LOCALE).as_ptr(), &mut index, &mut exists);
+        if hr != S_OK || exists == FALSE {
+            let hr = strings.FindLocaleName((*EN_US_LOCALE).as_ptr(), &mut index, &mut exists);
+            if hr != S_OK || exists == FALSE {
+                // Ultimately fall back to first locale on list
+                index = 0;
+            }
+        }
+
+        let mut length: u32 = 0;
+        let hr = strings.GetStringLength(index, &mut length);
+        assert!(hr == 0);
+
+        let mut name: Vec<wchar_t> = Vec::with_capacity(length as usize + 1);
+        let hr = strings.GetString(index, name.as_mut_ptr(), length + 1);
+        assert!(hr == 0);
+        name.set_len(length as usize);
+
+        String::from_utf16(&name).ok().unwrap()
+    }
+}
+
+// ToWide from https://github.com/retep998/wio-rs/blob/master/src/wide.rs
+
+pub trait ToWide {
+    fn to_wide(&self) -> Vec<u16>;
+    fn to_wide_null(&self) -> Vec<u16>;
+}
+
+impl<T> ToWide for T where T: AsRef<OsStr> {
+    fn to_wide(&self) -> Vec<u16> {
+        self.as_ref().encode_wide().collect()
+    }
+    fn to_wide_null(&self) -> Vec<u16> {
+        self.as_ref().encode_wide().chain(Some(0)).collect()
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/lib.rs
@@ -0,0 +1,80 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#![cfg_attr(feature = "serde_derive", feature(proc_macro, rustc_attrs, structural_match))]
+#![allow(non_upper_case_globals)]
+
+#[cfg(feature = "serde_derive")]
+#[macro_use]
+extern crate serde_derive;
+
+#[macro_use]
+extern crate lazy_static;
+#[macro_use(DEFINE_GUID)]
+extern crate winapi;
+extern crate gdi32;
+extern crate kernel32;
+extern crate libc;
+extern crate serde;
+extern crate dwrite;
+
+#[cfg(feature = "serde_codegen")]
+include!(concat!(env!("OUT_DIR"), "/types.rs"));
+
+#[cfg(feature = "serde_derive")]
+include!("types.rs");
+
+use winapi::DWRITE_FACTORY_TYPE_SHARED;
+use winapi::IDWriteFactory;
+
+use comptr::ComPtr;
+use winapi::S_OK;
+
+mod comptr;
+mod helpers;
+
+#[cfg(test)]
+mod test;
+
+// We still use the DWrite structs for things like metrics; re-export them
+// here
+pub use winapi::DWRITE_FONT_METRICS as FontMetrics;
+pub use winapi::DWRITE_GLYPH_OFFSET as GlyphOffset;
+pub use winapi::{DWRITE_MEASURING_MODE_NATURAL, DWRITE_MEASURING_MODE_GDI_CLASSIC, DWRITE_MEASURING_MODE_GDI_NATURAL};
+
+mod bitmap_render_target; pub use bitmap_render_target::BitmapRenderTarget;
+mod font; pub use font::Font;
+mod font_collection; pub use font_collection::FontCollection;
+mod font_face; pub use font_face::FontFace;
+mod font_family; pub use font_family::FontFamily;
+mod font_file; pub use font_file::FontFile;
+mod gdi_interop; pub use gdi_interop::GdiInterop;
+mod rendering_params; pub use rendering_params::RenderingParams;
+
+DEFINE_GUID!{UuidOfIDWriteFactory, 0xb859ee5a, 0xd838, 0x4b5b, 0xa2, 0xe8, 0x1a, 0xdc, 0x7d, 0x93, 0xdb, 0x48}
+
+unsafe impl Sync for ComPtr<IDWriteFactory> { }
+
+lazy_static! {
+    static ref DWRITE_FACTORY_RAW_PTR: usize = {
+        unsafe {
+            let mut factory: ComPtr<IDWriteFactory> = ComPtr::new();
+            let hr = dwrite::DWriteCreateFactory(
+                DWRITE_FACTORY_TYPE_SHARED,
+                &UuidOfIDWriteFactory,
+                factory.getter_addrefs());
+            assert!(hr == S_OK);
+            factory.forget() as usize
+        }
+    };
+}
+
+// FIXME vlad would be nice to return, say, FactoryPtr<IDWriteFactory>
+// that has a DerefMut impl, so that we can write
+// DWriteFactory().SomeOperation() as opposed to
+// (*DWriteFactory()).SomeOperation()
+#[allow(non_snake_case)]
+fn DWriteFactory() -> *mut IDWriteFactory {
+    (*DWRITE_FACTORY_RAW_PTR) as *mut IDWriteFactory
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/rendering_params.rs
@@ -0,0 +1,35 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use std::cell::UnsafeCell;
+
+use comptr::ComPtr;
+use winapi;
+use super::DWriteFactory;
+
+#[derive(Debug)]
+pub struct RenderingParams {
+    native: UnsafeCell<ComPtr<winapi::IDWriteRenderingParams>>,
+}
+
+impl RenderingParams {
+    pub fn create_for_primary_monitor() -> RenderingParams {
+        unsafe {
+            let mut native: ComPtr<winapi::IDWriteRenderingParams> = ComPtr::new();
+            let hr = (*DWriteFactory()).CreateRenderingParams(native.getter_addrefs());
+            assert!(hr == 0);
+            RenderingParams::take(native)
+        }
+    }
+
+    pub fn take(native: ComPtr<winapi::IDWriteRenderingParams>) -> RenderingParams {
+        RenderingParams {
+            native: UnsafeCell::new(native),
+        }
+    }
+
+    pub unsafe fn as_ptr(&self) -> *mut winapi::IDWriteRenderingParams {
+        (*self.native.get()).as_ptr()
+    }
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/test.rs
@@ -0,0 +1,103 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use winapi;
+
+use super::*;
+
+#[test]
+fn test_system_family_iter() {
+    let system_fc = FontCollection::system();
+    let count = system_fc.families_iter().count();
+    assert!(count > 0);
+    assert!(system_fc.families_iter().find(|f| f.name() == "Arial").is_some());
+}
+
+#[test]
+fn test_descriptor_round_trip() {
+    let system_fc = FontCollection::system();
+
+    let arial_family = system_fc.get_font_family_by_name("Arial").unwrap();
+    let arial_font = arial_family.get_first_matching_font(FontWeight::Regular,
+                                                          FontStretch::Normal,
+                                                          FontStyle::Normal);
+
+    let descriptor = arial_font.to_descriptor();
+    assert!(descriptor.family_name == "Arial");
+
+    let arial_font_2 = system_fc.get_font_from_descriptor(&descriptor).unwrap();
+    let descriptor2 = arial_font_2.to_descriptor();
+    assert_eq!(descriptor, descriptor2);
+}
+
+#[test]
+fn test_get_font_file_bytes() {
+    let system_fc = FontCollection::system();
+
+    let arial_family = system_fc.get_font_family_by_name("Arial").unwrap();
+    let arial_font = arial_family.get_first_matching_font(FontWeight::Regular,
+                                                          FontStretch::Normal,
+                                                          FontStyle::Normal);
+    let face = arial_font.create_font_face();
+    let files = face.get_files();
+    assert!(files.len() > 0);
+
+    let bytes = files[0].get_font_file_bytes();
+    println!("Bytes length: {}", bytes.len());
+    assert!(bytes.len() > 0);
+}
+
+#[test]
+fn test_glyph_image() {
+    let system_fc = FontCollection::system();
+    let arial_family = system_fc.get_font_family_by_name("Arial").unwrap();
+    let arial_font = arial_family.get_first_matching_font(FontWeight::Regular,
+                                                          FontStretch::Normal,
+                                                          FontStyle::Normal);
+
+    let face = arial_font.create_font_face();
+    let a_index = face.get_glyph_indices(&['A' as u32])[0];
+
+    let metrics = face.get_metrics();
+    println!("Metrics:\n======\n{:?}\n======", metrics);
+
+    let gm = face.get_design_glyph_metrics(&[a_index], false)[0];
+    println!("Glyph metrics:\n======\n{:?}\n======", gm);
+
+    let device_pixel_ratio = 1.0f32;
+    let em_size = 10.0f32;
+
+    let design_units_per_pixel = face.metrics().designUnitsPerEm as f32 / 16. as f32;
+    let scaled_design_units_to_pixels = (em_size * device_pixel_ratio) / design_units_per_pixel;
+
+    let width = (gm.advanceWidth as i32 - (gm.leftSideBearing + gm.rightSideBearing)) as f32 * scaled_design_units_to_pixels;
+    let height = (gm.advanceHeight as i32 - (gm.topSideBearing + gm.bottomSideBearing)) as f32 * scaled_design_units_to_pixels;
+    let x = (-gm.leftSideBearing) as f32 * scaled_design_units_to_pixels;
+    let y = (gm.verticalOriginY - gm.topSideBearing) as f32 * scaled_design_units_to_pixels;
+
+    // FIXME I'm pretty sure we need to do a proper RoundOut type
+    // operation on this rect to properly handle any aliasing
+    let left_i = x.floor() as i32;
+    let top_i = (height - y).floor() as i32;
+    let width_u = width.ceil() as u32;
+    let height_u = height.ceil() as u32;
+
+    println!("GlyphDimensions: {} {} {} {}", left_i, top_i, width_u, height_u);
+
+    let gdi_interop = GdiInterop::create();
+    let rt = gdi_interop.create_bitmap_render_target(width_u, height_u);
+    let rp = RenderingParams::create_for_primary_monitor();
+    rt.set_pixels_per_dip(device_pixel_ratio);
+    rt.draw_glyph_run(x as f32, y as f32,
+                      DWRITE_MEASURING_MODE_NATURAL,
+                      &face,
+                      em_size,
+                      &[a_index],
+                      &[0f32],
+                      &[GlyphOffset { advanceOffset: 0., ascenderOffset: 0. }],
+                      &rp,
+                      &(255.0f32, 255.0f32, 255.0f32));
+    let bytes = rt.get_opaque_values_as_mask();
+    println!("bytes length: {}", bytes.len());
+}
new file mode 100644
--- /dev/null
+++ b/third_party/rust/dwrote/src/types.rs
@@ -0,0 +1,74 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* this is include!()'d in lib.rs */
+use std::mem;
+
+// mirrors DWRITE_FONT_WEIGHT
+#[repr(u32)]
+#[derive(Deserialize, Serialize, PartialEq, Debug, Clone, Copy)]
+pub enum FontWeight {
+    Thin = 100,
+    ExtraLight = 200,
+    Light = 300,
+    SemiLight = 350,
+    Regular = 400,
+    Medium = 500,
+    SemiBold = 600,
+    Bold = 700,
+    ExtraBold = 800,
+    Black = 900,
+    ExtraBlack = 950,
+}
+
+impl FontWeight {
+    fn t(&self) -> winapi::DWRITE_FONT_WEIGHT { unsafe { mem::transmute(*self) } }
+    pub fn to_u32(&self) -> u32 { unsafe { mem::transmute(*self) } }
+    pub fn from_u32(v: u32) -> FontStretch { unsafe { mem::transmute(v) } }
+}
+
+// mirrors DWRITE_FONT_STRETCH
+#[repr(u32)]
+#[derive(Deserialize, Serialize, PartialEq, Debug, Clone, Copy)]
+pub enum FontStretch {
+    Undefined = 0,
+    UltraCondensed = 1,
+    ExtraCondensed = 2,
+    Condensed = 3,
+    SemiCondensed = 4,
+    Normal = 5,
+    SemiExpanded = 6,
+    Expanded = 7,
+    ExtraExpanded = 8,
+    UltraExpanded = 9,
+}
+
+impl FontStretch {
+    fn t(&self) -> winapi::DWRITE_FONT_STRETCH { unsafe { mem::transmute(*self) } }
+    pub fn to_u32(&self) -> u32 { unsafe { mem::transmute(*self) } }
+    pub fn from_u32(v: u32) -> FontStretch { unsafe { mem::transmute(v) } }
+}
+
+// mirrors DWRITE_FONT_STYLE
+#[repr(u32)]
+#[derive(Deserialize, Serialize, PartialEq, Debug, Clone, Copy)]
+pub enum FontStyle {
+    Normal = 0,
+    Oblique = 1,
+    Italic = 2,
+}
+
+impl FontStyle {
+    fn t(&self) -> winapi::DWRITE_FONT_STYLE { unsafe { mem::transmute(*self) } }
+    pub fn to_u32(&self) -> u32 { unsafe { mem::transmute(*self) } }
+    pub fn from_u32(v: u32) -> FontStretch { unsafe { mem::transmute(v) } }
+}
+
+#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
+pub struct FontDescriptor {
+    pub family_name: String,
+    pub weight: FontWeight,
+    pub stretch: FontStretch,
+    pub style: FontStyle,
+}
--- a/toolkit/library/gtest/rust/Cargo.lock
+++ b/toolkit/library/gtest/rust/Cargo.lock
@@ -121,17 +121,17 @@ source = "registry+https://github.com/ru
 dependencies = [
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dwrote"
 version = "0.1.0"
-source = "git+https://github.com/vvuk/dwrote-rs#7112cf6e4bb9f645217dacb5d7470178da13a544"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "dwrite-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_codegen 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -563,17 +563,17 @@ dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "dwrote 0.1.0 (git+https://github.com/vvuk/dwrote-rs)",
+ "dwrote 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -587,17 +587,17 @@ dependencies = [
 
 [[package]]
 name = "webrender_traits"
 version = "0.9.0"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "dwrote 0.1.0 (git+https://github.com/vvuk/dwrote-rs)",
+ "dwrote 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_codegen 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -639,17 +639,17 @@ dependencies = [
 "checksum cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8bdd78cca65a739cb5475dbf6b6bbb49373e327f4a6f2b499c0f98632df38c10"
 "checksum cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283"
 "checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd"
 "checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5"
 "checksum core-graphics 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "66e998abb8823fecd2a8a7205429b17a340d447d8c69b3bce86846dcdea3e33b"
 "checksum core-text 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2debbf22a8358e5e270e958b6d65694667be7a2ef9c3a2bf05a0872a3124dc98"
 "checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
 "checksum dwrite-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7918280f33862bc8542212d74f2149b1a87ab402fd15f4ce9a1c56582958d6e"
-"checksum dwrote 0.1.0 (git+https://github.com/vvuk/dwrote-rs)" = "<none>"
+"checksum dwrote 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "65c6ec960350000aaeb2ae745e63d01f225a5485d537c8e265a12a781ed1fdf0"
 "checksum euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "44ef2a3e4a621518e488db36820a12b49a9d5004764b8daf1458bbe5d7c9b626"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum freetype 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a89563eaf185762cf495c56cb16277549d2aaa7b1240d93338e8429fa33acd1"
 "checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
 "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
 "checksum gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1d8edc81c5ae84605a62f5dac661a2313003b26d59839f81d47d46cf0f16a55"
 "checksum gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b04d6c8a1df841e48dfe99ed67829c9d1d17b1bb3e44c5f3283992010e20359b"
 "checksum heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8c80e194758495a9109566134dc06e42ea0423987d6ceca016edaa90381b3549"
--- a/toolkit/library/rust/Cargo.lock
+++ b/toolkit/library/rust/Cargo.lock
@@ -119,17 +119,17 @@ source = "registry+https://github.com/ru
 dependencies = [
  "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
 name = "dwrote"
 version = "0.1.0"
-source = "git+https://github.com/vvuk/dwrote-rs#7112cf6e4bb9f645217dacb5d7470178da13a544"
+source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "dwrite-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_codegen 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -550,17 +550,17 @@ dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bincode 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-text 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "dwrote 0.1.0 (git+https://github.com/vvuk/dwrote-rs)",
+ "dwrote 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "freetype 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -574,17 +574,17 @@ dependencies = [
 
 [[package]]
 name = "webrender_traits"
 version = "0.9.0"
 dependencies = [
  "app_units 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "core-graphics 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "dwrote 0.1.0 (git+https://github.com/vvuk/dwrote-rs)",
+ "dwrote 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
  "heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
  "ipc-channel 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "offscreen_gl_context 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_codegen 0.8.17 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -626,17 +626,17 @@ dependencies = [
 "checksum cgl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8bdd78cca65a739cb5475dbf6b6bbb49373e327f4a6f2b499c0f98632df38c10"
 "checksum cmake 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0e5bcf27e097a184c1df4437654ed98df3d7a516e8508a6ba45d8b092bbdf283"
 "checksum core-foundation 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "20a6d0448d3a99d977ae4a2aa5a98d886a923e863e81ad9ff814645b6feb3bbd"
 "checksum core-foundation-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "05eed248dc504a5391c63794fe4fb64f46f071280afaa1b73308f3c0ce4574c5"
 "checksum core-graphics 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "66e998abb8823fecd2a8a7205429b17a340d447d8c69b3bce86846dcdea3e33b"
 "checksum core-text 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2debbf22a8358e5e270e958b6d65694667be7a2ef9c3a2bf05a0872a3124dc98"
 "checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
 "checksum dwrite-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7918280f33862bc8542212d74f2149b1a87ab402fd15f4ce9a1c56582958d6e"
-"checksum dwrote 0.1.0 (git+https://github.com/vvuk/dwrote-rs)" = "<none>"
+"checksum dwrote 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "65c6ec960350000aaeb2ae745e63d01f225a5485d537c8e265a12a781ed1fdf0"
 "checksum euclid 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "44ef2a3e4a621518e488db36820a12b49a9d5004764b8daf1458bbe5d7c9b626"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
 "checksum freetype 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a89563eaf185762cf495c56cb16277549d2aaa7b1240d93338e8429fa33acd1"
 "checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
 "checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
 "checksum gl_generator 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1d8edc81c5ae84605a62f5dac661a2313003b26d59839f81d47d46cf0f16a55"
 "checksum gleam 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b04d6c8a1df841e48dfe99ed67829c9d1d17b1bb3e44c5f3283992010e20359b"
 "checksum heapsize 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8c80e194758495a9109566134dc06e42ea0423987d6ceca016edaa90381b3549"