Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - PiotrGrochowski

Pages: [1]
1
The entire category of Text Layouting is something unknown to the FreeType library, because layouting is out of scope for FreeType.

However, it is important to focus on Text Layouting anyway. It is out of scope for FreeType, yet in scope for TD renderer and is expected to be an important part of the Type Design ecosystem.

Text Layouting involves finding ways to layout all text. It is not a trivial task due to newlines (0x000D 0x000A), surrogates (0xD800 to 0xDBFF, 0xDC00 to 0xDFFF), wraps (when text line would be wider than the text box) and tab stops (0x0009).

Character Positioning is finding ways to position all characters. Standards Unicode handling, like special Arabic forms and Thai combining and so on, is out of scope for the standard method because it will be extremely complex.

What then, is the standard method?

This is what it looks like:

Before any read of input text we find the font top and font bottom. This should be determined in OpenType fonts by taking WinAscent and WinDescent and scaling it to the ppem size and rounding (half pixel rounds away from baseline in font height boundaries). In raw bitmap font format there is no concept of baseline but the font height boundaries are implicit to be the top and bottom of the bitmap after the font width and font height are known.

The font top and font bottom, the difference being the font height. It is critical because every line advances by font height amount of pixels.

Now we can start interpreting. Assume UTF-16 is being used to render from. What to render? The first character? Not yet. We have to keep special rules throughout Text Layouting.

We render the characters, the rules:

0x0009 is the tab, write a 0x0020 character and advance to the next tab stop after the current position, the distance between tab stops is to sum widths of 0x0041 to 0x005A and sum widths of 0x0061 to 0x007A and take the sum of that, add 26 and divide by 52, multiply by 8.

0x000D 0x000A is the newline. This specific sequence will move the current position to the beginning of the line, then move down by the font height.

0xD800 to 0xDFFF are surrogates. Use the UTF-16 rule to interpret a pair of surrogates, 0xD800 to 0xDBFF followed by 0xDC00 to 0xDFFF, as a code point. It is still rendered as a single character.

The wrap rule. Not everything will fit, so an auto wrap is used. Wraps may occur on space (0x0020) or tab (0x0009). Find the largest extent of text that will fit before a space or tab, then render it as well space or tab (possibly beyond the bounds). After a space or tab hanging beyond bounds there may not be another such space or tab, it must go on another line, moving down by the font height.

The select rule: Render all characters in the selection range in the selection foreground and background instead of the text box foreground and background. When a tab is selected, the entire extent of tab is selected, not the rendered space character.

Cursor inversion: The cursor is placed on the current position a single pixel horizontally covering the font height vertically. It inverts the colors.

Cursor on the right: If the vertical cursor would be rendered to the right beyond the bounds it is rendered on the right edge instead

2
Quadratic Pixel Building / Re: Quadratic Formula
« on: September 26, 2020, 06:27:42 pm »
The best known way is Six Pass Pixel Building:

1. Trace all edges on the left side, rounding the vertical boundaries of bezier curve to the nearest (if half, up) and increment the pixel values of all pixels to the right. (first pass)
2. Trace all edges on the right side, rounding the vertical boundaries of bezier curve to the nearest (if half, up) and decrement the pixel values of all pixels to the right. (second pass)
3. Create a new pixel buffer, and do steps 1 and 2 but rounding half down instead. (third and fourth pass)
4. Merge the pixel buffer into the main buffer by taking the maximum value of each.
5. Trace all edges on the top side, rounding the horizontal boundaries of bezier curve to the nearest (if half, up) and increment the pixel values of all pixels below. (fifth pass)
6. Trace all edges on the bottom side, rounding the horizontal boundaries of bezier curve to the nearest (if half, up) and decrement the pixel values of all pixels below. (sixth pass)
7. Now each inside pixel is of value 2, or 1. Each value greater than 0 or less than -1 is a filled pixel.

Done! Now go do dropout control on https://pixelbuilding.createaforum.com/quadratic-pixel-building/dropout-control/

3
Quadratic Pixel Building / Dropout Control
« on: September 26, 2020, 06:27:35 pm »
The quadratic formula as estabilished in https://pixelbuilding.createaforum.com/quadratic-pixel-building/quadratic-formula/ is seen to properly handle half pixel borders.

But how does Drop Out Control does work? It's even more complicated than the Quadratic Formula. TD renderer 1.0 got it completely wrong, and TD renderer 2.0 improved it TD renderer 3.0 fixed some bugs too. The Pixel Building community is currently unaware of the exact specific Dropout Control method that should be used to properly render.

This is what came up with:

1. Track fractional edge positions in a fractional format while doing Quadratic Formula
2. Keep track of eight pixel arrays, assume extending up to 2 pixels from any standard render bounds, clamp any stored edges to one pixel beyond render bounds (2, 4, 5, 6, 7, 8, a, b)
3. clear 2, 4, a, b with the zero value
4. for each top edge (starting from the last one) increment the value in the array 2. if the value is 1 set the value in array 5 to the difference between fractional and integer values
5. for each bottom edge (starting from the last one) increment the value in the array a. if the value is 1 set the value in array 6 to the difference between fractional and integer values
6. for each left edge (starting from the first one) increment the value in the array 4. if the value is 1 set the value in array 7 to the difference between fractional and integer values
7. for each right edge (starting from the first one) increment the value in the array b. if the value is 1 set the value in array 8 to the difference between fractional and integer values
8. for each pixel from top to bottom from left to right if the value in arrays 4 and b if neither of the two pixels next to the edge if no stub detection or there exists any of the three edges next to the edge on either side if smart dropout control and the fractional edge is closer to the right pixel but not exceeding standard glyph bounding square subtract 2 from the pixel to the right of the edge else subtract 2 from the pixel to the left of the edge
9. for each pixel from top to bottom from left to right if the value in arrays 2 and a if neither of the two pixels next to the edge if no stub detection or there exists any of the three edges next to the edge on either side if smart dropout control and the fractional edge is closer to the up pixel but not exceeding standard glyph bounding square subtract 2 from the pixel to the up of the edge else subtract 2 from the pixel to the down of the edge
10. free 2, 4, 5, 6, 7, 8, a, b

But this is unfortunately an unworkable system for proper dropout control! This is because it does not properly handle some cases when dropout is close to the middle.

Please do note the dropout control system is dependent on the point order. The reason is depending on the point order the dropout control finds a different pair of edges out of more than two possible edges and this makes the smart dropout direction differ.

Also note that there are many renderers not properly using this dropout control mechanism. Edge dropout control glitching is when in FreeType it fails to properly parse dropout controls from top to bottom (as a drawn dropout control pixel affects the result of the dropout control pixels below it), and fails to make it properly dependent on the point order.

4
Quadratic Pixel Building / Quadratic Formula
« on: September 19, 2020, 04:46:52 pm »
The main way to turn quadratic outlines into pixel borders. This must be done twice horizontally and once vertically for correct rendering, for proper handling of half pixel corners later. This step is followed by Pixel Building inside the borders, done in one pass each for the top and bottom edges, and two passes each for left and right edges. The possibility of missing extrema is ignored.

First, we have to turn the Quadratic Bezier into a Quadratic Polynomial: for each dimension, given the points a, b, c, the quadratic function where f(0)=a and f(1)=c (curve goes from 0 to 1) is (a)x⁰+(2*(b-a))x¹+((c+a)-(2*b))x².

We have the quadratic polynomial, (q)x⁰+(w)x¹+(e)x². In both horizontal and vertical dimensions, where the curve goes from 0 to 1.

We apply this rule: For each half pixel position (let's say, j) along a dimension we place an edge. First we apply the Quadratic Formula to determine at what location on the curve the coordinate is located.
It is located at
double r = j-q; double t = w/(-2.0*e); double y; if(1.0/t == 0.0) y = r/w; else if(t<0.5) y = t+sqrt((t*t)+(r/e)); else y = t-sqrt((t*t)+(r/e)); return y;
With the location now known, it is possible to determine where the edge would be. On the other dimension, we simply do (q)x⁰+(w)x¹+(e)x² with the obtained location. It must then be rounded to nearest integer. For half-rounding note that because pixels on TOP of the outline are inside, half-edges on the top and right are rounded up, while half-edges on the bottom and left are rounded down.
The Quadratic Formula is absolutely necessary to rasterize quadratic outlines. It can be figured out with a lot of mathematical thinking, however it is very common to make mistakes in implementation of it.

Pages: [1]