Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement downloadable fonts on Windows #15096

Merged
merged 1 commit into from Jan 19, 2017
Merged

Conversation

@vvuk
Copy link
Contributor

vvuk commented Jan 18, 2017

This PR implements downloadable font support for Servo. It depends on new changes in webrender and dwrote, and adds a dependency on the truetype crate for pulling out basic font information. The original DirectWrite API does not provide an easy way to query font information direct from a FontFace (which is what you create from a FontFile). There are new DirectWrite APIs starting with Windows 10 that allow for this, but they are Win 10+ only, and winapi-rs does not yet have bindings for those versions of the interfaces (specificially, IDirectWriteFontFace3). The way to do this with DW is to go through a lot of pain in creating a custom collection and enumerator, add your font to your custom collection, then query the collection for its properties.

Instead, we just parse the truetype tables directly to pull out the few bits of information that we need. The truetype crate is ok, but I discovered some bugs (an update needs to get pushed to crates.io before this will build). It might be more worthwhile to just implement the tiny bit of truetype parsing that we need ourselves in Servo.

I'm guessing there are existing tests for downloadable fonts...


  • ./mach build -d does not report any errors
  • ./mach test-tidy does not report any errors
  • These changes fix #__ (github issue number if applicable).
  • There are tests for these changes OR
  • These changes do not require tests because _____

This change is Reviewable

@highfive
Copy link

highfive commented Jan 18, 2017

warning Warning warning

  • These commits modify unsafe code. Please review it carefully!
  • These commits modify gfx code, but no tests are modified. Please consider adding a test!
@@ -40,11 +42,211 @@ impl FontTableMethods for FontTable {
}
}

fn make_tag(tag_bytes: &[u8]) -> FontTableTag {
assert!(tag_bytes.len() == 4);

This comment has been minimized.

Copy link
@emilio

emilio Jan 18, 2017

Member

nit: If you use assert_eq! this will display the length in the eventuality that it fails.

This comment has been minimized.

Copy link
@emilio

emilio Jan 18, 2017

Member

well, though it's only used statically.

style: FontStyle::Normal,
};

if let Some(mut name_table_bytes) = face.get_font_table(make_tag(b"name")) {

This comment has been minimized.

Copy link
@emilio

emilio Jan 18, 2017

Member

nit: Maybe this would be a bit cleaner if you do something like:

let mut name_table_bytes = match face.get_font_table(make_tag(b"name")) {
    Some(table) => table,
    None => return Err(()),
};

// Use name_table_bytes here.

This applies also to other places below.

@jdm jdm assigned emilio and unassigned jdm Jan 18, 2017
@vvuk
Copy link
Contributor Author

vvuk commented Jan 18, 2017

truetype 0.24.0 was just published to crates.io; going to rebase this

@vvuk vvuk force-pushed the vvuk:custom-font-files branch from 4d24edc to 704c945 Jan 18, 2017
@vvuk vvuk force-pushed the vvuk:custom-font-files branch from 704c945 to a9611c3 Jan 18, 2017
@vvuk
Copy link
Contributor Author

vvuk commented Jan 18, 2017

Rebased and addressed review comments

@jdm jdm removed the S-needs-rebase label Jan 18, 2017
Copy link
Member

emilio left a comment

Looks reasonable to me. Haven't audited the truetype crate, but it's (co-?)authored by @vvuk, so I think we can account you as responsible for it :)

License-wise it's fine (just for the record).

I've left mostly stylistic comments since most of the job is done in truetype.

r=me with it addressed

let mut face_name_index = None;

for i in 0..records.len() {
// the truetype crate can only decode mac platform format names

This comment has been minimized.

Copy link
@emilio

emilio Jan 18, 2017

Member

Should we support this? If so, consider filling an issue and referencing it here.

This comment has been minimized.

Copy link
@vvuk

vvuk Jan 18, 2017

Author Contributor

Probably? I actually don't think we ever use the family and face name from downloaded fonts, since I believe you specify those in the @font-face anyway. If someone can confirm that, we can change this around to just give dummy UUIDs or something for family/face, and then the only thing left would be the OS/2 table, which is very simple to parse... in which case we could just do everything ourselves.

continue;
}

if records[i].language_id != 0 {

This comment has been minimized.

Copy link
@emilio

emilio Jan 18, 2017

Member

Same for this I guess.

let names = try_lossy!(NamingTable::read(&mut name_table_cursor));
let (family, face) = match names {
NamingTable::Format0(ref table) => {
if let Some((family_index, face_index)) = get_family_face_indices(&table.records) {

This comment has been minimized.

Copy link
@emilio

emilio Jan 18, 2017

Member

My previous comment also applied here and in the Format1 arm, though this is not a big deal.

This comment has been minimized.

Copy link
@vvuk

vvuk Jan 18, 2017

Author Contributor

Yeah; these were more compact so I didn't change them. I don't really like the mass duplicated code here anyway, but short of refactoring a bunch of stuff out I can't think of how I'd change it.

// names. We want name_id 1 and 2, and we need to use platform_id == 1 and
// language_id == 0 to avoid limitations in the truetype crate. We *could* just
// do our own parsing here, and use the offset/length data and pull the values out
// ourselves.

This comment has been minimized.

Copy link
@emilio

emilio Jan 18, 2017

Member

Maybe make this a doc comment?

@vvuk
Copy link
Contributor Author

vvuk commented Jan 18, 2017

Looks reasonable to me. Haven't audited the truetype crate, but it's (co-?)authored by @vvuk, so I think we can account you as responsible for it :)

Welllllllll... I made on PR for it, I don't know that it makes me an author :)

I filed #15103 for maybe fixing the language/encoding issues.

@emilio
Copy link
Member

emilio commented Jan 19, 2017

Oh, FYI you appear in the author list on https://crates.io/crates/truetype :)

Well, I opened #15105 and bodoni/truetype#5 regarding possible security implications we may need to care about in medium/long term.

Meanwhile this is ok to land IMO.

@bors-servo r+

@bors-servo
Copy link
Contributor

bors-servo commented Jan 19, 2017

📌 Commit a9611c3 has been approved by emilio

@bors-servo
Copy link
Contributor

bors-servo commented Jan 19, 2017

Testing commit a9611c3 with merge 1a7404e...

bors-servo added a commit that referenced this pull request Jan 19, 2017
Implement downloadable fonts on Windows

This PR implements downloadable font support for Servo.  It depends on new changes in webrender and dwrote, and adds a dependency on the `truetype` crate for pulling out basic font information.  The original DirectWrite API does not provide an easy way to query font information direct from a `FontFace` (which is what you create from a `FontFile`).  There are new DirectWrite APIs starting with Windows 10 that allow for this, but they are Win 10+ only, and `winapi-rs` does not yet have bindings for those versions of the interfaces (specificially, `IDirectWriteFontFace3`).  The way to do this with DW is to go through a lot of pain in creating a custom collection and enumerator, add your font to your custom collection, then query the collection for its properties.

Instead, we just parse the truetype tables directly to pull out the few bits of information that we need.  The `truetype` crate is ok, but I discovered some bugs (an update needs to get pushed to crates.io before this will build).  It might be more worthwhile to just implement the tiny bit of truetype parsing that we need ourselves in Servo.

I'm guessing there are existing tests for downloadable fonts...

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #__ (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15096)
<!-- Reviewable:end -->
@bors-servo bors-servo merged commit a9611c3 into servo:master Jan 19, 2017
2 of 3 checks passed
2 of 3 checks passed
continuous-integration/appveyor/pr Waiting for AppVeyor build to complete
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
homu Test successful
Details
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

5 participants
You can’t perform that action at this time.