Hacker Newsnew | past | comments | ask | show | jobs | submit | vorporeal's commentslogin

1. I guess the answer is that it is both global and local? An application window draws its contents to a buffer (basically, an RGBA image), which the operating system can copy to the buffer that represents the full contents of the screen. The buffer for a given window is effectively a grid of pixels; when we lay out the contents of our application, we compute an (x,y) position and (w,h) size for each primitive (whether a rectangle or a glyph). These four values (x,y,w,h) don't have to be integral, but if they're not, some extra work has to be done in order to correctly set the colors of the buffer's pixels that "sit beneath" the objects that we're drawing.

2. We do use Core Text, in fact, via a cross-platform Rust library called font-kit. It provides shaping and glyph rasterization APIs for us, but for performance reasons, we cache the results of shaping at a line level but the results of rasterization at a glyph level (as individual glyphs frequently appear in multiple places in a single frame).

3. We're currently delegating rasterization to Core Text; I'm not sure what it uses internally. My sense is that most of the development of new rasterization strategies is for applications like game engines, which need to be able to draw text efficiently at a variety of scales, a requirement that doesn't apply for a terminal. We prioritize crispness of text (and, to some extent, consistency with text rendering in other applications) over size scalability, as people will spend a lot of time reading text at a single size.

4. That's a good question, and I don't have an answer handy. We load (most) font data in the background, as we only use two fonts at any time (one for monospace text, like in the terminal grid, and one for UI strings). We currently don't do any shaping in the terminal grid (and therefore don't support ligatures there). That said, we cache shaping results at a per-line level and rasterization results at a per-glyph level, so don't need to do either step frequently. In aggregate, over a user session, the vast majority of the time will be spent "copying" an already-rasterized glyph from our atlas to the window's backing buffer.


From my research, it seems like SDF is a best suited for game engines to use for text, especially non-UI text (that may appear at arbitrary sizes), as it is a fast, space-efficient, and easily scalable approximation.

Unfortunately, SDF tends to lose precision at corners, making it less good for text-oriented applications. It does seem like multi-channel SDF improves on the corner precision issues (as highlighted by the repo you linked to), but in a terminal, we don't frequently need to render text at different scales, so not sure there is much benefit. (If a user changes font sizes, we can clear out and rebuild the atlas sufficiently quickly.)

That said, I could borrow some ideas from MSDF to improve on space efficiency by encoding the three different offset variants into separate color channels at the same atlas location, reducing size of the atlas itself as well as the hashmap used to look up atlas position from glyph ID and whatnot.


Good call-out - definitely a bit of a simplification there. We account for this in our terminal grid by allocating an empty cell following any double-width glyphs (e.g.: emoji and wide chars, as you mentioned).

Tried out your example in Warp, and the alignment is as you described: https://i.ibb.co/Jcwcnwn/image.png

Core Text supports rasterizing at sub-pixel offsets (though some configuration of the graphics context is necessary to do so properly) by applying a transformation to the graphics context before the rasterization call. I'll definitely have to figure out the FreeType angle when we start working on Linux support; if I uncover anything (and remember this comment thread), I'll report back with my findings. :)


Blog post author here - great questions.

My understanding is that some, but not all, shaping libraries will handle fallback fonts. For example, I believe Core Text (on MacOS) will specify which sections of a laid-out line should be rendered using which fonts, factoring in fallback font selections. Kerning should work within a run of a single font, but I'm not sure there's any way to "properly" kern a glyph pair from two separate fonts - there wouldn't be any information available about proper alignment (as kerning data is part of a font file). In terms of sizing, one would hope that font creators all respect the em-square when constructing glyph vectors, leading to two different fonts using the same point size having comparably-sized glyphs. If one doesn't want to rely on that, font metrics like ascent and descent could be utilized in an attempt to normalize sizing across different fonts.

In terms of cache size: at the moment, we rarely empty out the cache (but we should do it more often). I have some ideas around triggers for emptying the cache and letting it get rebuilt (e.g.: changes to font size, changes to font family), but haven't wired it up yet. In addition, we could consider clearing the cache periodically when the application is sitting in the background (allowing us to re-rasterize the needed glyphs without blocking painting a frame). So tl;dr: we don't currently but we should and will do so in the future.


Thank you for the answers! I built a rust lib to generate multi-channel signed distance field font texture. I wanted to make it a text rendering lib. But after learning how complex it is, I guess I should give up and simply use core text...


MSDF seems like a great choice, depending on your use-case. Given that we don't need to draw text at multiple scales, it doesn't seem to provide much benefit for us over caching rasterized glyphs provided by Core Text. (Copying a rasterized glyph is certainly faster than evaluating an SDF.)

Using Core Text also means our text looks the same as it does in other applications, which avoids bug reports from users like "text in Warp looks different than in iTerm". :)


This seems to be due to Google's new grouping of permissions for Android apps. The permission group you're referring to is described as "Uses one or more of: files on the device such as images, videos, or audio, the device's external storage". That means that if the app wants to use some of its own data which is located on external storage (which is pretty common), you're also giving it permission to access your media files on the device, because Google thinks (for some incomprehensible reason) that these are similar permissions and grouping them makes it easier for users to understand what's going on.


>Google thinks (for some incomprehensible reason) that these are similar permissions and grouping them makes it easier for users to understand

Yeah, I suppose they don't want to be too granular and overwhelm users with a ton of permissions but, to your point, it actually makes things worse. Overly broad categories lead to suspicion.

It's funny though, because for years, we all downloaded/installed desktop apps which had free reign on our machines. I suppose the facts that apps can come from untrusted sources, are thought to have more specific functions, are installed on very personal devices, and were born in an age where privacy concerns/fraud/malware/connectedness were common, all have something to do with it.

I wonder, though, if our concern is mostly stimulated by the fact that we're now being presented with permission choices in the first place. As, now, even "trusted" brands like HBO can earn our suspicion if we think their apps are being greedy with permission requests.


Same, I use Terminus at 8pt as my terminal font, and it's fantastic - dense yet readable.


This is the fault of your implementation, not the pattern. Event types (names) should be enums, not arbitrary strings. This makes it very easy to change the way the code reads if the meaning of the event slightly changes, and equally easy to obfuscate the event key in a production build.


You would need a static js compiler to type check the enum. So that's an extra step. This doesn't happen in Java or C, but browser based event models (the topic of the post) are almost always strings. Most front end shops choose this implementation. You could add that step to your build, sure, but in. Lot of cases the app is already interpreted so there is no "build" per se. Who else has seen this?


You can make them properties on a global object, so that using an invalid event name is at least a runtime error (when you try to bind to an undefined event) rather than being mystified about why the event never triggers.


You still need a runtime test to find the error though, which I why manual QA is required.


The primary issue is that the design is very obviously driven by the goal of monetization. On my laptop, the top half of the page is dominated by the navigation bar at the top (starting with "Premium Membership") and the "Learn From Proven Entrepreneurs" box, featuring a giant "Go Premium?" button, which ends up being right in the middle of the page. I'd estimate that <20% of the space above the fold is useful content.

In addition, there are a number of polish issues that exacerbate the spammy feeling caused by what I described above. There's an escaping bug in the title of the login widget on the right side ("YOU\'RE LOGGED OUT"). You use a number of different background colors (the search widget has a blue one, the "What's new here" has an off-white one). There are too many groups of social media buttons (on the left of the main container, under the search box, under the video clip). There are a lot of horizontal and vertical separators, and they have differing styles and amounts of padding.

Hope that helps!


Social and Promotions should basically just contain the "unimportant crap". If something is mis-categorized, you can drag it to the correct section and Gmail should learn from its mistake.

Also, as mentioned below, you can revert to the un-tabbed inbox by going to the Inbox section of the settings and disabling all tabs other than Primary, or by selecting one of the split inboxes (Unread first, Priority, etc).

Disclaimer: I'm a Gmail engineer.


Why have tabs when there's already priority inbox, labels, and filters?

It seems like the new feature is essentially just a way to do automatic (learned?) labeling -- yet it won't let you build your own tabs using already-defined custom labels. :-/


> If something is mis-categorized, you can drag it to the correct section and Gmail should learn from its mistake.

The mistake is making me worry about this shit in the first place.

> Also, as mentioned below, you can revert to the un-tabbed inbox by going to the Inbox section of the settings and disabling all tabs other than Primary, or by selecting one of the split inboxes (Unread first, Priority, etc).

Thank you.


When I receive "unimportant crap," I either unsubscribe to the list that sent it, or mark it as spam.

I do not leave crap lying around and then add another management dimension to my Inbox to deal with it.


There are things that are interesting - news of upcoming band tours, shipping updates, phone bills - but not of importance when I first check my emails in the morning.

Plus, it has the added benefit that emails which land in anything but the main inbox don't notify your phone, removing a distraction.


I wish I could give you more than one upvote. Perhaps even a googol of them.


Hi Vorporeal,

May I contact you with a Google question? I've encountered a technical problem which I would like to report, but I am having trouble finding an appropriate communication channel. The technical problem itself is interfering with my ability to use the typical channels.

If you are willing to help point me in the redirect direction, then please contact me via the info in my profile. (I was hoping to contact you privately, but your profile is blank.)

I won't harass you, and I don't expect support from you personally - I'm just hoping you might be able to point me in the right direction, in terms of how to report the tech problem.

Thank you!


> and Gmail should learn from its mistake

Do you mean "Policy is against giving users any meaningful ability to train their filters, but if Neptune is in the Third House, Gmail might learn from its mistake"?


Wow. I just discovered this new misfeature is on my android Gmail app and didn't go away when I killed it on the web version. Where's the option to kill social and promotions on the Gmail app?


Check the account-specific settings within the app.


Oddly enough unchecking the social and promotions categories doesn't work with the gmail app (the change is not retained). Guess I'll file a bug...

Thanks.


I think it's more of "The information you requested, were it to exist, would be highly classified (due to its type), and therefore we can neither confirm nor deny its existence."


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: