Skip to content

Monday, 31 October 2022

Personally I haven’t ever been a big user of tiling windowmanagers such as i3, awesome and what not, is not much the workflow style I want 24/7 out of my desktop, but there is definitely something something to say about that kind of multitasking when it makes sense, when is important to see the status of multiple windows at once for some particular task.

Plasma’s KWin has since a long time a basic support for tiles via the quick tiling support, by either dragging a window at edges or corners, or via keyboard shortcuts. This feature is very good, but very basic, and while there are 3rd party tiling extensions such as Bismuth which is a very nice thing, but window geometry managing outside the core always can bring you only so far.

Over the last month I have been working to expand a bit the basic tiling capabilities, both the quick tiling with the current behavior and a more advanced UI and mechanism which lets the user to have a custom tiling layout. Here it is a very short screencast about it.

tiling manager effect

Tiling is done by a full screen editor done as a fullscreen effect where is possible to add /remove/resize tiles. When moving a window if the Shift modifier is pressed, the window will be dropped in the nearest tile. Resizing the tile in the editor will resize all the windows connected, and on the converse, resizing tiled windows will resize the tiles as well. (also the traditional split screen quick tile will gain this feature, so if you have 2 windows tiled to get half of the screen each, resizing one will resize both)

Another use case we thought about for this tiling feature is to address people which have those fancy new ultra wide monitors.

Random stock photo from the interwebs of an ultra wide screen

There are very few applications which have an UI that actually make sense maximized on such proportions (i could imagine perhaps KDEnlive, Krita and very few other productivity apps). Most applications just look wrong, but with custom tiling areas, those can become sub “maximization” zones.

It is not intended to be a full fledged replacement for I3 or Bismuth, but rather an hopefully robust mechanism in the core with a pretty minimal and unobtrusive default ui, then the mechanism will have scripting bindings which should allow for 3rd party extensions to use it and implement interesting variations of the tiling WM out of it.

For now the feature is quite basic, a notable thing missing which i still hope to get in time for 5.27 is having separate tiling layouts per virtual desktop and activity (for now they’re per-phisical screen), but hopefully the full thing should land on a Plasma 5.27 release near you.

Window outlines! Yet another KDE contribution by yours truly! This was fun. Not easy at all, but fun. I'm pretty happy how they turned out.

Breeze Dark

Outline Dark

Breeze Light

Outline Light

I hope Nate you don't mind me taking the screenshots from your blog post, I'm just.. Lazy. I have no excuse. Lol.

For those who just want to see how it's made, here's link to the merge request: https://invent.kde.org/plasma/breeze/-/merge_requests/241

Also I am probably gonna make couple LOTR references due to talking about binding and light and dark and I'm sorry about that beforehand.

But why make them?

I have big problem making distinctions between windows if they have dark theme and on top of each other. Window shadows are often dark as well, so the windows just kind of blend into each other and the shadows do not help much. Disable shadows altogether and you got windows that just disappear into each other. This can even happen with light themes, sometimes the shadows just are not enough.

They also look a bit better with the outlines, in my opinion. They give some kind of "constraint" for the window and they ease my weird brain.

To sum up, it just makes the windows feel like they're their own entities which calms my brain, they look nice and they stop windows from blending into each other.

Where are they drawn?

First I had to figure out where the hecc I draw these outlines?

Well, I wanted to make them their own thing, separated completely from other elements. But this would've meant I would need to actually make more in-depth modifications to KDecoration (I think?) and make the outlines their own draw calls and whatnot.

So instead, I made them play nice with shadows. Basically, the outlines are just part of the shadow drawcall.

But what happens if shadows are disabled?

Something cheeky happens! I actually draw the shadows with 0% alpha channel!

    CompositeShadowParams params = lookupShadowParams(m_internalSettings->shadowSize());
    if (params.isNone()) {
        // If shadows are disabled, set shadow opacity to 0.
        // This allows the outline effect to show up without the shadow effect.
        params = CompositeShadowParams(QPoint(0, 4), ShadowParams(QPoint(0, 0), 16, 0), ShadowParams(QPoint(0, -2), 8, 0));
    }

So the shadows are always there, they're just invisible. But the outlines will show up.

Hold on, you could've just skipped drawing shadows entirely!

Yes, but actually no.

Before shadows are even drawn, they make some very very useful calculations for me. And on top of that, remember that outlines are part of the shadow drawcall. Outlines are just one more colored part of the shadow, basically.

No shadows, no outlines. In darkness together, I've bound them.

Bordering madness

I get it all look nice and fancy with borders, they look all nice and rounded on bottom border... And then I disable borders.

And everything looks off.

The bottom border disappears completely and leaves a sharp window edge. The outline then rounds behind the window. It looks bad!!!

Outline Bad

So, if borders are disabled, we do a magic trick and draw the outline path on our own.


    // Draw window outline
    const qreal outlineWidth = 1.001;
    const qreal penOffset = outlineWidth / 2;

    // Titlebar already has an outline, so move the top of the outline on the same level to avoid 2px width on top outline.
    QRectF outlineRect = innerRect + QMarginsF(penOffset, -penOffset, penOffset, penOffset);
    qreal cornerSize = m_scaledCornerRadius * 2;
    QRectF cornerRect(outlineRect.x(), outlineRect.y(), cornerSize, cornerSize);
    QPainterPath outlinePath;

    outlinePath.arcMoveTo(cornerRect, 180);
    outlinePath.arcTo(cornerRect, 180, -90);
    cornerRect.moveTopRight(outlineRect.topRight());
    outlinePath.arcTo(cornerRect, 90, -90);

    // Check if border size is "no borders"
    if (borderSize(true) == 0) {
        outlinePath.lineTo(outlineRect.bottomRight());
        outlinePath.lineTo(outlineRect.bottomLeft());
    } else {
        cornerRect.moveBottomRight(outlineRect.bottomRight());
        outlinePath.arcTo(cornerRect, 0, -90);
        cornerRect.moveBottomLeft(outlineRect.bottomLeft());
        outlinePath.arcTo(cornerRect, 270, -90);
    }
    outlinePath.closeSubpath();

This part was actually fixed by Noah Davis: https://invent.kde.org/plasma/breeze/-/merge_requests/241#note_541478

So, uh, I'm not 100% sure what's going on here but it seems that:

  • Draw a rectangle with top left and top right with an arc, since they're always rounded
  • Check if we have border on or off
  • Draw bottom corners with an arc if borders are on, or draw sharp lines if they're off

I think I got it right..? But I can say, my solution was more messy and I'm glad it's not there. It involved basically blending two rectangles together. This is much better!

Outline colors!

The biggest puzzle of this was actually how to get the color for the outlines. We could have just gone with basic black and white coloring here, but it would be too much contrast in some situations and look jarring to some.

So I started with a simple idea: Take the background color of the window, then light or dim it based on its lightness value (HSL). If lightness is equal or over 50%, then dim the color. Otherwise lighten it.

At first I used HSV, which caused a bit weird situations. In HSL, lightness is basically how much the color is lightened or darkened, but in HSV, the value dictates how the color acts under light. For this situation HSL was better since we're not playing with lighting values, but just want to know if the color is "dark" or "light" to our eyes.

Anyhow, here's some copy-pasta from the source files:

    auto s = settings();
    auto c = client().toStrongRef();
    auto outlineColor = c->color(c->isActive() ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::TitleBar);

    // Bind lightness between 0.1 and 1.0 so it can never be completely black.
    // Outlines only have transparency if alpha channel is supported
    outlineColor.setHslF(outlineColor.hslHueF(),
                         outlineColor.hslSaturationF(),
                         qBound(0.1, outlineColor.lightnessF(), 1.0),
                         s->isAlphaChannelSupported() ? 0.9 : 1.0);

Hold on, you said background color of the window, but you're using titlebar color?

When using the background color ColorRole::Frame the problem is that when having colored titlebar, the outline color feels very out of place. It just doesn't look good.

But using ColorRole::TitleBar we get a fun colored outline effect when having a separately colored titlebar!

Outline Colored

Also there's the whole qBound(0.1, outlineColor.lightnessF(), 1.0) thing. Like the comment says, if the lightness value is black or very dark, the outline will also be black or very dark. Binding the lightness avoids situations where the outline blends into the dark background color.

And of course, finally we check if transparency is enabled and set it accordingly to avoid awkward situations.

But colors are tricky. Some like this solution, some don't. I am probably going to make a drop-down setting where people can select does the outline use background or titlebar color, or are they just off.

Continuous Iteration

My part was done and the outlines got merged! It was long long long ride and I learned a lot. But I'm super happy I managed to do this part, now it just needs to be iterated on so we can get something that looks The Best.

Nate Graham already made the colors pop a bit more by fixing the lighten/darken values: https://invent.kde.org/plasma/breeze/-/merge_requests/263

Also there was initially a feature that if the window color was super light, we just didn't show outlines at all due to the outlines being so dim it created a weird blur effect as the outlines were gray, the shadow black and the window white. But with this tweak that doesn't need to be done anymore.

There's still probably work to be done on this, but the biggest hurdle seems to be over! Knocks on wood

As I said, I may make the settings section for this, but we'll see. I need a short break from KDE contributions, I got my own projects to work on too lol.

There's also been talk that we could use the separator (the | thing that separates buttons in menus etc etc) color as the outline color, and make that separator color modifiable. I think that would make A Lot Of Sense... But I would still keep the outline color as the titlebar color if the titlebar is colored. :)

Thanks!

Thanks for reading this ramble. I really enjoyed making this contribution and once again I learned A LOT. Open source contributions are great way to learn new stuff and I'm happy I get to make stuff like this for KDE. Also I've learned I kinda enjoy writing C++!

And thanks for all the comments and feedback and code reviews and everything anyone did to help me get this outline thing through. Based on the feedback I've read on Da Internets, this is something many people didn't realise they needed!

Sunday, 30 October 2022

The past few months I’ve been rewriting the text layout engine used by Krita’s text tool. This is not the same as the text tool itself, which is still a super small rich text editor, but it is a prerequisite to getting any kind of new features into the text shape. We haven’t done any real improvements to text since the work for the last fundraiser we had for it, and that is because this needed to be done, it is a lot of work, an we had vowed to take care of resource management first, which, uh, took us so long and was so intensive that it covered the whole development cycle from 4.0 to 5.0, or a span of 5~ years. I’m not the only developer who can finally tackle a sore point, there’s work being done on audio, lots of file format updates, work on assistants, technology upgrades and more… But this blog is about text.

Some history:

The purpose of text in Krita is to provide artists an easy way to add text to images. One of the primary cases being to add text to comics, but other uses, such as adding small paragraphs of text, captions and creating headers are also accepted. It does not have to be able to show pages of text, or be able to fill the whole canvas, but it is expected that artists can convert a text to a path so they can make fine grained adjustments. The latter is usually used for sound effects in comics and graphical titles.

We previously used QTextLayout for our text shape layout. QTextLayout is used for Qt’s own text, in its labels and text edits. We initially had hoped it would be sufficient for putting text on an image, but sadly we kept coming across issues, partially ones caused by SVG having more complex needs, but also ones that were caused by QTextLayout no being designed for anything but Latin text. This includes things like no support for vertical text layout, but also, more painfully, certain kinds of technical choices which lead to decorative properties like underlines breaking joined scripts. We had to disable accelerators for our menus because of this; they made text that uses Arabic look glitchy. We also had an interesting bug caused by Qt setting the scaling on a text object in a way that we can’t access when only using QTextLayout, meaning all our font-sizes were wrong.

XML based markup like SVG in addition has some features which can only be computed as long as you understand the markup to be applied on a tree of nodes, while a lot of text layout engines like to think of them as ranges of text that have a format applied to them. This and other SVG specific features mean that we need to be able to customize how certain features are done significantly, and when using QTextLayout that generally resulted in a lot of workarounds, which in turn made the code quite intimidating.

Pango is another commonly used text layout engine, specifically the one used by all GTK projects. Inkscape uses it for its text layout. However, studying Inkscape I found that they too had workarounds for Pango, which, after the hell that was dealing with QTextLayout was something I had no interest in. Far more troublesome is that I couldn’t figure out how to use Pango without Cairo. Cairo is a painting engine, specifically one that is used by the likes of Scribus and Inkscape for its vector drawing capabilities. But the thing is that we already have two painting engines inside Krita, the one used for text and vector being QPainter, and our own KisPainter. KisPainter is the one that is fully colour managed and also the one we optimize the most, and I would like it if we could at some distant point switch our vector shape drawing code to KisPainter as well, primarily because it’s the one that can handle floating point depths and also the one we do all the optimizations on. So adding Cairo just to draw text seems to go into the exact opposite direction I’d like to go in.

Scribus is interesting here because while it uses Cairo to draw, it doesn’t use Pango and has its own text layout code. The biggest difference between Scribus and Krita in this regard is that being a Desktop Publishing program, text layout is one of the core features of Scribus, so I imagine for them it was a case of “we absolutely need full control of the code”, where with Krita we would’ve been fine with a halfway solution as long as it didn’t result in bug reports that we couldn’t fix because we were using a library in a way it was never expected to be used.

At the same time, you absolutely don’t want to start from scratch. So our text layout doesn’t implement its own Unicode functions and algorithms, using libraries like Fribidi, libunibreak and Qt’s own offerings where it can, as well as using fontconfig for locating fonts and Freetype for retrieving glyphs from the font. The library that has made everything possible however has been Raqm which handles itemization (breaking text up in runs of similar font and script), calling Fribidi for the bidirectional algorithm and finally calling Harfbuzz for shaping (selecting the correct glyphs for a given string of text). We were able to submit patches for UTF 16 support, as well as some other small things, and it has greatly simplified laying out text, to the point I was able to get the basics of SVG 1.1 text up and running in about… A week or so. The only downside for us as KDE project is that it requires Meson+pkgConfig, while KDE projects generally use CMake. Harfbuzz too seems to be going this route, so it can’t be helped.

So, having laid down which dependencies we’re using I am now going over the peculiarities and problems I encountered in… The order I am making/updating the relevant automated tests.

Going over the tests.

Now, you might be thinking: “Shouldn’t you start with tests when dealing with some so reliant on an official spec?” And you’d be right, and I did always have tests that I checked against. They just weren’t automated:

My testing sheet filled with all sorts of random test samples.

The benefit of a big sheet like this is that, aside from looking cool, was something I could load into Inkscape and Firefox from time to time to see how compatibility was looking.

The real reason I avoided tests was because we already had a ton of tests, and a lot of them were broken to begin with, which probably never had much to do with whether they actually worked but rather that the fonts weren’t available. Which brings us to the first topic:

Font Selection.

So, typically font selection in Qt goes via QFontDatabase, which is both its own database as well as a front end to the various platforms preferred font selection mechanisms. I had not wanted to touch this, as it is perfectly decent at its job, save for the fact it behaves weird when you try to learn the font-stretch of a given QFont (it always reports 0). Sometimes you come across applications which keep hanging on the “font loading” stage, or which lag when you open up the font combo box, and this is because they don’t cache the fonts. QFontDatabase does, which makes it a huge pity that there’s no way to get ones hands on the filename of a given font. And we need that, because we need those to load the relevant Freetype faces. So one of the first things I had to implement was using Font Config to get the fonts.

The way FontConfig is typically used is that you create a pattern to which you add the things you want to search for. This is stuff like family names, but also font-weight (in combination with the FcWeightFromOpenType function), italics, and most usefully language. Fontconfig apparently keeps a list of characters for each language, allowing you to specify a language and it will then give preference to fonts that have characters for that language. This is kind of neat, given that a lot of font families need to be split up into smaller files because font files are (currently) not able to encode a glyph for each Unicode code point. I’m telling you all this because this isn’t actually written in the documentation, I had to read a whole lot of existing code and issues on trackers to learn this myself.

On the flip side, we can now implement some CSS features QFontDatabase wouldn’t make possible, like a list of font families for fallback. For this I am first creating the pattern, then calling the sort function. Then I take the text I am matching for, and split that up into graphemes using libunibreak. Then for each grapheme I try to find the best match for the whole grapheme and mark those as needing that font.

You want to do this for the whole grapheme because emoji sequences for example are joined by zero width joiners, and if you do per codepoint matching instead of thee whole grapheme, this might get matched to a different font, which means that during the itemization process (where Raqm takes the text and splits it up into runs of text with the same font and script to pass it to Harfbuzz) the parts of the sequence will end up in different runs, meaning Harfbuzz cannot select the appropriate glyph for that sequence. If you have the problem where an emoji sequence looks like a sequence instead of a single emoji despite the font supporting it, this is the reason. Emoji aren’t the only place were this happens, though it is the easiest to test. Variation selectors and combination marks are also best used with the same font, but this is much harder to test for folks who don’t speak languages that use either. Anyway, the matched graphemes are then merged into bigger runs of the same font, and then passed to Raqm.

I still have no idea whether this is going to work on on all platforms, given fontconfig is very Linux specific.

The first tests I created in this area were a test for the grapheme breaking (given we rely on libunibreak for this, it is more a test for our code that splits a string into a string list based on libunibreak’s guidance), and a test for loading fonts that are part of the unit tests. Technically, CSS does have mechanism for adding outside font files with @font-face, but our parser doesn’t support that feature, and implementing it could get quite complicated, with additional questions like ‘should we then support embedding fonts in .KRA files?’, so for now it’s a much simpler method that is only available to the tests.

Now able to ensure we have the test fonts available, the next two tests were ones adapted from the web-test-platform: A test for selecting bold, and one for selecting fonts of the correct font-weight on a font with OpenType variations (not to be confused with CSS font-variant, or with Unicode Variation Selectors). The later broke because we tried to cache the fonts to speed up layout, which meant that that if you configure the same font for multiple variations (or font-sizes), it would only use the last configuration.

More font tests followed.

Better font fall backs for unicode variation selectors.

The Unicode variation selectors needed custom test fonts which contained a glyph, and then another with both a glyph and a variation selector, because what we want in the end is that if no font has a given glyph and a variation selector, it should take the next best font (the one with only the glyph). Unicode graphemes start with the most important codepoint first, so this is a case of keeping around partial matches if no complete match was found.

Bitmap fonts.

Most fonts these days are vector based instead of raster based, and while we need to render to bitmap to display the glyphs eventually, Krita instead takes the glyph outline from Freetype and renders that by itself later. This allows us to support things like color gradient and pattern fills as well as SVG strokes for the text outline. Still, there are fonts out there without outlines, often quite old.

Now, Krita’s support for rendering these isn’t great, because the way our vector layer coordinate system works is that everything is in Points (1/72th an Inch), and we cannot figure out how many pixels there are per inch (PPI) inside the vector shapes. This is both kind of a pain for bitmap fonts, but also for glyph outlines, as font-hinting will result in Freetype returning adjusted outlines depending on what it thinks the PPI is. This is very much a legacy thing that dates back to the time of KOffice, but no one has ever had the time to look into it…

… And neither did I, right now there’s a hack in place that surmises the PPI during the painting code and based on changes there it runs the text layout algorithm. It isn’t great, but it works. For the test I made a quick bitmap font using FontForge with several different sizes for a single glyph. The code is then checked on which size it will select depending on which size is requested. This is important for color fonts as one of the types of color font (which are used for Emoji) is a bitmap font. There’s one big difference between old fashioned pixel fonts and the new color pixel fonts, and that is that the latter should get resized to the desired size if the selected size is too big. I haven’t put in a test for that, because I have no color bitmap font (specifically of the CBDT type) to test with yet.

After those tests, it was finally time for the main event.

SVG 1.1 tests.

Text support in SVG 1.1 allowed for laying out a single line of rich text, and then applying transformations to it. So we can move around and rotate specific glyphs, make them follow a path, or use text length to squeeze or stretch them into a specific shape, and finally, you can select whether a text is anchored at the start, middle or end.

The most common misconception I’ve seen regarding SVG 1.1 text is the notion of a text chunk. Some people think they are what tspans define, that is, a styled chunk of text, but they’re not. They are an absolutely positioned pieces of text, which can be anchored in different ways. The official SVG 2.0 algorithm even calls them ‘Anchored Chunks’, which is probably the better name. This is important, because SVG 2.0 introduces a big change with regard to text chunks. Before, each text chunk had to be shaped separately, now, all text chunk are laid out in one go meaning that shaping (which is necessary for joined scripts like Arabic) doesn’t break across boundaries as long as the font object doesn’t change. There’s some discussion in issue 631 about whether this is undefined behaviour and thus can differ between implementations, but the SVG 2.0 text layout algorithm makes this implicit, as it says to layout SVG 1.1 text as a single line of unbounded length with a CSS-based text renderer. CSS-based text renderers don’t know about SVG text chunks, so shaping (and bidirectional algorithm) behaviour is defined. This has consequences, but more on that later.

This is the point where in test land I started fixing the old tests. To my pleasure, most of the tests had merely some anti-aliasing differences between QTextLayout and my implementation. So I mostly spend time ensuring that the necessary font is loaded, and then took the string of SVG that was being tested and made it into an external file so I could occasionally check in other programs how they handled the test.

Some of the tests actually got extended a little. For the transforms I had to add test for vertical, as well as test for per-glyph-rotation, as we had neither before. For the test where we test whether different fills can be applied to different part of the text, I added ligatures and a combining mark to see how it would handle that. What is supposed to happen is that the first color assigned to a grapheme is used for the rest of the grapheme, even if the rest of the code points are assigned a different color, as this gives the most consistent result. Interestingly, this only works with font-caching enabled, as that ensures spans that have otherwise the same font will also use the same font object, meaning it won’t get split up during itemization (and Harfbuzz, which handles the ligatures cannot create them when they are in different runs of text). We generally don’t want that to happen (because it messes up joined scripts), so we’re going to need to find a way to solve that.

Here, the top sample is correct, and the bottom sample wrong, as the bottom sample breaks up the FFI ligature and gives different colors for the circumflexes on the A. This is because the different spans have separate font objects assigned despite the same font being assigned to the whole text.

Among the tests that broke were attribute tests, because in the shift to SVG 2.0, glyph-orientation-vertical which takes an angle, needs to be switched to text-orientation, which takes keywords, and more such small conversion problems. Texts orientation allows for controlling whether glyphs for horizontal scripts get rotated when being laid out in vertical text. Krita doesn’t do much with this attribute, as we still need to implement support for it in Raqm.

As an aside, you might be wondering how we’re dealing with some of the more intricate features of CSS, like padding, and stuff like display:table-block. And the answer is that we don’t have to: all child nodes of a text in SVG can only be inline, and SVG doesn’t use the CSS box model. This is because it would otherwise truly become too complicated.

The old test that gave me the most trouble was the right to left text. Now, here is were it starts to become ‘interesting’. The actual bug I had was fixed because I had forgotten to set the first absolute xy position to 0,0 if it was not set otherwise, but I still kept getting issues. You see, when I open it up in different browsers, I get different results:

My result in Krita was the same as that of Firefox, and it looked really wrong. Chromium looks the most correct here, right. However, after much contemplation, Firefox is correct. This is a side effect of SVG 1.1 text being laid out in a single line, as it means bidi-reordering is done over the whole paragraph. So a right-to-left text with two text chunks, which respectively end and start with left-to-right text, will have those end parts flipped around.

If you color the spans that are associated with the two chunks, the bidi-reordering problem becomes very obvious.

And then when we start positioning the text, a gap appears because of the flip of the two sets of glyphs. Arguably you could fix this by repositioning those glyphs so they’re snug together, or maybe something can be done with the bidi algorithm control points. I’m kind of hesitant however, because we’re not laying out a line (which would warrant the bidi algorithm to be only applied on the characters in the line, after line breaking), we’re positioning a logical chunk of text… So I’m unsure what to do here, and had to conclude Firefox is correct. I’ve submitted an issue to the SVG working group tracker.

Anyway, after this adventure, you can imagine why all the new tests are in triplicate: One for left-to-right, one for right-to-left and one for vertical.

TextLength

TextLength is an SVG feature where text is stretched or squashed to fit a particular length, with an option to only transform the spaces in between letters or the glyphs themselves. It can be nested, meaning that a tspan with this feature enabled can have a child node that also has a textLength.

The SVG 2.0 algorithm for this is mostly correct. Because it is possible to have nested text length, it needs a recursive function: you go down the tree, first handling the text length of child nodes, and then that of the parents.

There is two things it misses though: glyphs that follow a stretched piece of text need to be adjusted too, until the end of the anchored chunk. Furthermore, all glyphs need to be adjusted in the ‘visual order’, that is, the order after the bidirectional algorithm is done with it, not the ‘logical’ (pre-bidi) order. This means that if you’re done with a node, you need to afterwards look forwards (or backwards for right-to-left) until the next anchored chunk begins or the text ends, note down the visual index, and then adjust these glyphs in the visual order, with the total amount of shift that the text length causes, as long as their visual index is higher than the one you adjusted last.

Also, the SVG 2.0 algorithm is setup for adjusting spacing only, meaning that the last character is not taken into account for the shift-delta nor adjusted. If you are transforming both spacing and glyphs you will want to include the last character so everything stretches nicely.

Krita’s result for the test of textLength, with each color representing a different test-case. The XO is actually from one of the test-fonts I made for Unicode Variation Selectors, being repurposed because a proper CJK font takes up several dozens of MBs, and thus isn’t very suitable to store inside git.

After all these adjustments, text length starts working as it says it should work, and you’ll have a perfectly working SVG 1.1 feature no one really uses. So, from there we’ll now go to the SVG 1.1 feature that everyone wants to use…

Text on Path

Being able to arrange text so it follows a path is a pretty common use case for the kind of typesetting that tries to mimic calligraphy and lettering (whether these are two separate disciplines depends on how you approach calligraphy). So greeting cards, poster titles, etc.

The SVG 2.0 algorithm is clear here, and you should follow it. However, there’s a few caveats unique to features in SVG 2.0.

Collage of the textPath tests I am not discussing in detail, from top-left to bottom-right: Test of ‘side’, test of textPath + svg transforms, test of multiple textPaths in a single text element, text of closed paths, basic text path test, and finally test of the startOffset attribute.

First up is that the first absolute xy transform on the first glyph in a textPath element needs to be set to 0,0, because otherwise you get problems with multiple textPath elements in one single text element.

Secondly, SVG 2.0 allows for trailing spans of text that is outside the path, but not in a new text chunk, and the spec says, “hang these at the end of the path”. This mostly works, except, of course, with right-to-left text.

Chromium looks correct, but it’s kind of wrong in a sneaky way, because this is the text flow:

This is probably what is expected, but algorithm-wise that is the start of the path:

Double checking, it seems that right to left text-on-path was just never really considered, and every implementation I have tried will not show right-to-left text unless the start offset is at 100%, which is on some level weird. So I have made an issue out of that.

Before I go on to discuss text-wrapping, there’s two more side things to discuss:

Baseline alignment

Baseline alignment was part of SVG 1.1, and it allows text to be adjusted based on metadata inside the font, but in SVG 2.0 it’s supported through CSS-inline, here it’s folded into vertical-align. So, technically speaking if you get your text out of a CSS-based text renderer, like the algorithm suggest you do, you shouldn’t have to worry about this. We’re not doing that, so I had to implement this myself.

Initially I had wanted to make it part of Raqm, given it seemed something that everyone could use, but I quickly failed at doing so, as baseline alignment is applied tree-wise. Once I figured that out, it was relatively easy to implement, as SVG 1.1’s description is fairly straightforward:

Make a recursive function that first makes a table or map of baseline meta-data that is inside the first font of the given text span (with fallbacks as defined by CSS inline), then go over each child node and call this function again, passing them this table. Finally, use the table and the table the function got from the parent node to adjust the glyphs.

Fonts that carry baseline meta data are kind of rare though, so it’s best to have defaults to fall back to, and in particular to use Harfbuzz 4.0, which has such defaults built-in. For the tests, I ended up using a test-font from here.

Text Decorations

This comprises of underlines and strike-throughs. Even if this should be something that is handled by the suggested CSS-based text-renderer, you will probably want to do your own implementation of this, if you want to have good looking underlines while text is on path. I had some trouble with this as no one had really figured this out, but eventually I found something out that made me happy:

You will need to make a recursive function, that first calculates the child-nodes, and passes the textPath path down to them if there is one. Then, you will wan to calculate the text-decoration boxes by joining the bounding boxes of the glyphs in the span in a way so that each text-chunk inside the span has it’s own decoration box. These are then used as the source for generating over lines, underline, strike-throughs, etc.

Now, for text-on-path, if you’re smart and know how to offset bezier curves, you should proly offset a part of the original path that corresponds to the width of each decoration box. I’m not that smart, so instead I create, per decoration box, a polyline which is as wide as the decoration box, but has a node every 4*underline stroke width (in the case of the “wavy” decoration-line-style, every other node is moved down 4*underline width as well, so it creates a nice even zig-zag). Then I use the same method as used for positioning text on path to adjust each node, and finally I use QPainterPathStroker to turn the path into a proper shape. These are then cached in the object that represents the text span, so that I can draw them before and after drawing the glyphs as CSS3-text-decoration wants, with the correct span colour and everything.

The SVG spec doesn’t say how it expects text-decoration to look when putting text-on-path, but I suspect this is what is expected by most people using text-on-path, and am pretty pleased with the results.

You will want to do this before doing the text-on-path alignment, so the glyphs have not been adjusted yet.

You can use per node offsets to stretch glyphs on path as well, with the caveat that straight parallel sections would be best off to be replaced by an offset bezier curve section, and this is especially necessary for Devanagari (as the connector line in fonts is usually a straight line), despite not doing that, I am keeping this around as a proof of concept.

The difference between stretched text (red) and regular text-on-path is subtle in most cases, but the glyphs do join up nicely when using it.

So after all this, there’s the final important feature…

Inline-size

SVG 2.0’s biggest feature is the several text-wrapping options it introduces, some being simpler than others, and these are really necessary as doing paragraphs of text with simple chunk positioning is a headache. Inline-size is the simplest of these wrapping options, as it only says “wrap at this width”, with nothing really special going on there.

While my initial idea was to focus on SVG 1.1 features, I did want to get this in, as it requires a line-breaking library, so if we included this now, we wouldn’t need to add new dependencies for a while (at the least, until we want to hyphenate I guess). I later discovered that having libunibreak in was really useful because grapheme breaking helps a lot with font-selection. Anyway, right now we don’t have support for things like wrapping inside a shape yet, as I tried to focus on inline-size and text wrapping features.

The inline-size test, testing direction, both of the vertical writing modes and all of the text-anchors for each. Note how the first line aligns with a light-blue line: This is because the position of a text with inline-size is the starting position of the text, so the first line’s baseline should align with a line in the same position.
Inkscape is the only software I have available to me that supports inline-size. It seems that when you use transform=”translate()” Inkscape 1.2 positions the text in weird ways, it does align properly when using the x and y attributes instead.

There’s noting exciting here, a typical example of the greedy line-wrapping algorithm: Get libunibreak to find wrapping points, count the logical characters until you find a wrapping point, check if the total advance is higher than inline size, if not, add “word” to line (and adjust characters, etc.), else start new line and move word there, adjust previous line for line height reasons.

As you may guess from the word “line”, there was bidirectional algorithm things here too. officially, the bidirectional algorithm need to be applied after line breaking, but for us it happens before line breaking, because Raqm (via FreeBidi) handles it. And indeed, after I had implemented all CSS-text-3 things like overflow-wrap and line-height, I noticed that my bidirectional text was wrong, and that was the point at which my morale broke.

The order of “SVG 1.1 SE” is incorrect for right-to-left line-wrapping.

For a week. I managed to get a sort of fix by switching from counting in the visual order to the logical order and then recalculating the advance, which works fine for implicit bidi-reordering, but I need to investigate what happens when we introduce bidi-controls, which is fine-tuning for the algorithm that shouldn’t be necessary most to the time, but does exist for special edge-cases. In the worst case we’ll have to get wrapping to happen in Raqm, but if we ever want to have hyphenation, we might need to do that anyway…

Bidi reordering is now part of the special cases inline-test, together with different font-types, text-decoration and supplementary plane characters like emoji (as these take up 2 codepoints in UTF-16 instead of 1, so it can have unusual results if there’s a bug in the text-wrapping).

Other than that, inline-size is a bit peculiar in that it defines the wrapping box as starting at the anchor, and ending at the width of the inline-size, with text-anchor (not text-align!) defining how the text is distributed. This makes sense from a specification stand point, as it means it is possible for a renderer to implement a simple as possible text-wrapping without immediately committing to CSS-text-3, though it does mean any kind of justification isn’t possible yet.

Wrapping inside a shape does allow for this, but I am going to implement that as a separate patch, partially because this one was becoming too big, and partially because I had no clear plan on how to tackle this when I decided the that no more new features were to be added to the current work. That said, I did go through all of CSS-text-3 to see which features I could implement…

Text-transform

The feature that allows you to set all text in all-caps, or lowercase, as a styling thing, without affecting the text itself. Where the complexity with East-Asian scripts is the sheer number of glyphs, and the complexity with joined scripts is that they have complex shaping rules, the complexity with Latin, Greek and Cyrillic is that at some point clerks in Europe decided that Important Words were going to have their first letter written in the slower formal strokes, while the rest of the letters would be written in the faster less formal strokes. Every language using these “Bicameral” scripts has on top of that their own rules what constitutes Important Words, some have their own rules which lowercase letter corresponds to which uppercase letter, and finally, there’s also different rules on how VERY IMPORTANT TEXT should look.

Thankfully, most of this case-mapping is thoroughly documented by Unicode, and if you have access to a library of Unicode functions it will have uppercase and lowercase functions at minimum. It does mean however that we need to have a language assigned to a text (line breaking and many font features require this too), and this is possible for text now, but I still need to figure out how to take the language set on the Krita document and have it be inherited as the default on text shapes which live in vector layers. Another thing which I am thinking of is whether we might be able to offer spelling check as a way to encourage artists to select the appropriate language for the text so it gets the best possible layout, though there is plenty more to do before I can do that.

That means that in Krita’s case we handle text-transform uppercase and lowercase by using QLocale’s to upper and lower functions. It’s going to be interesting how well this works, because these rely on ICU’s functions first, and then falls back on operating system functions and we don’t build ICU for Krita, by there’s a non-zero chance operating specific functions use ICU themselves.

For capitalization (which CSS simplifies to every first character of a word), you can get pretty far by finding every grapheme that follows a CSS word separator character and then only doing uppercase on those. You’ll have to create some language specific exceptions, like for example for Dutch to check if a J follows an I, because “Ijsbeer” reads like some kind of geographic feature, while “IJsbeer” is a Polar Bear.

Then there are two functions for East-Asian text layout, one to ensure the largest letters are chosen in situations where the text is very small, and the other to ensure that text lays out nicely in vertical situations. Full-size kana is a case of mapping the characters as defined by the table inside the CSS-text-3 specification. Full-width mapping in our case maps the relevant ASCII to the Unicode codepoints in the full-width and half-width forms page. For the rest, I use QChar’s decompositionTag() to see if “narrow” is part of it, and if so, replace with the decomposed form. Under the hood this also uses Unicode functions.

For the tests, I had wanted to adapt the ones for the web-platform-tests, but it seems that one tests all possible letters that have an uppercase, which was a bit too much for me, so I went with a greatest-hits version that tests the Latin alphabet, some Turkish text for the I, and then adapted the tailoring tests.

The downside of not implementing the uppercase function myself is that here is one test for Greek I don’t grasp. Namely, Greek uses diacritics, tonos, for lowercase text, but when the text is set to all-caps these tonos are removed (or reordered?). The uppercase function used by QLocale does all that. However, apparently this is not the case with capitalization. And I am unsure how to check for that, as I am unsure what is expected of these tonos. So I kind of need help here.

Same thing with the kana and half-width tests, with former testing some Katakana and Hiragana, an the latter with a bit of Latin, some half width katakana, some Hangul and a bunch of punctuation.

Line-break, word-break and overflow-wrap.

These are all was to refine the way line-wrapping is handled, with line-break largely handled by libunibreak (it supports strict and normal, we may need to patch it if we want loose at some point). Word-break is missing break-word because I didn’t have the concentration for it, spending it instead on overflow-wrap, which controls what happens when the words are too long to wrap.

Overflow wrap is particularly useful as it gives alternative automated options. In reality I suspect people will want to hand-wrap, but if they don’t have the time, the option is there. I’m seeing now that the first line isn’t handled correctly in all cases, so I’ll need to go back.

Hyphenation technically belongs with them as well, but would require adjusting Raqm as shaping will need to be redone when hyphenation happens inside a ligature, in addition to using a library/hyphenation dictionary for the actual breaking. I’m delaying all that, as hyphenation is uncommon for text on images.

Line-height

This controls how far the lines are apart. The spec says that line-height:normal is up to the renderer, but the percent and ratio-based values are pretty well defined.

Line-height in Inkscape 1.2

I have dyslexia, and while there’s different text-layout adjustments that help different people with dyslexia, mine is best served with bigger spacing between the lines, so I was kinda pleased I managed to get this to work.

The line-height test in Krita.

White-space

White-space controls what happens with multiple spaces in a sequence, and replaces xml:space property as used by SVG 1.1. The white-space property for SVG 2.0 needs to use the one from CSS-text-4 because it needs to provide a correct fallback for xml:space="preserve". I managed to get some of this implemented, but I am not testing it yet and will have to go back to double check everything, because our parsing code removes duplicate white-spaces by itself, and that needs to be undone carefully.

Example showing the debug boxes I use to figure out what the text-layout thinks the different boxes represent. Cyan is nothing special, Magenta is either a text-anchor or the start of a line, yellow is a space that can collapse according to the current white space rules, and boxes with a blue dot in them qualify as soft-breaks. You can tell some of the white space rules are applied already, as none of the lines end with a yellow box with a blue dot in them (being collapsed). I suspect however they are taken into account for line-breaking, which may account for why Krita’s line breaking is different from Inkscape’s.

Text-indent and tab-size

Text indent indents the first line, or all lines but the first. I got both hanging and regular text-indent to work, but can’t test each-line, because the parsing code is still removing hard-breaks as one of the white spaces it removes. When I was doing the tests I had another bug with right-to-left text, but this time it had nothing to do with bidi-reordering for a change. Rather, I had mixed up negative and positive values for right to left meaning that when I intended to subtract the text-indent value, I was instead adding it.

We were already testing tabs, so I extended that old test to also test tab-size.

Hanging-punctuation

Hanging punctuation is when you let punctuation go outside of the wrapping area. This is particularly nice with justified text, and I suspect it may also give less messy word-wrapping if the wrapping algorithm is allowed to consider some punctuation as being outside the boundaries. Hanging punctuation is a potential solution for this, which is why it made sense to me to implement it…

A sample of working hanging-punctuation, the Latin and Arabic text use first and last, while the vertical text uses first, last and allow-end for the vertical-rl, and first, last, force-end for the vertical-lr.

… And then I discovered that no one else has a full implementation of it, and that even Adobe InDesign doesn’t have it, making me very worried. Like, on a rational level I know it is likely because nobody wants to mess with their perfectly functional line wrapping code, but on some level I am worried it is actually because hanging punctuation is known to cause computers to eat puppies or something.

Final tests

After the inline tests I spend some time on adapting the CSS font-variant property tests on the web-platform-tests to SVG. These control whether OpenType features like ligatures and different character styles are applied during shaping. Krita previously only supported small caps, but with more direct access to Harfbuzz (OpenType support being one of its core features), it was easy to get this to work. It was mostly a case of copy-pasting the correct CSS-properties to be parsed, and then assembling a list of features for the given range and let Harfbuzz handle the rest. Right now only the CSS-fonts-3 features are supported, as CSS-fonts-4 requires parsing of @rules, which Krita doesn’t do yet.

The final test I wrote was a render test for ColrV0 fonts, using some OpenType test fonts from here. Krita officially supports ColrV0 and CBDT, but I still need font for the latter. I need to double check what is up with SBIX, and after that, the two big color fonts types are SVG and ColrV1. I didn’t bother with these yet, as I hadn’t figured out how to cache them properly (which is necessary both because of color palettes, as well as allowing the text to be converted to paths). I think I may have an idea how to now, but there’s more important things to be done first, and I suspect I still have a year or so before anyone starts to miss them. As with the font variants, @rules are not supported yet, so @font-palette-values isn’t either.

Future work

I am currently trying to clean stuff up, with my colleagues helping me with getting everything to build and helping me speed things up. Font-caching is a thing that absolutely needs to be done properly (maybe I should make sure that we can reuse it for the @rules later?). Text on path is a bit slow right now, and we may be able to speed that up. I am still kind of worried about the speed of the rendering, but we may need to make benchmarks before I can communicate my worries more clearly.

After that, I want to finish up the text-wrapping work, so we have proper white-space and text-in-shape handling. Probably fix bugs here and there too.

Then… doing preparation work so we have an interface to change text programmatically without having to write and parse SVG XML strings. And doing research, because there’s some common focus issues with on-canvas text tools that I’d really like to avoid.

After or intermediary to that I’d also like to get more improvements to East-Asian text layout, like text orientation, emphasis marks, and maybe even ruby (may seem unnecessarily ambitious, given there’s no other implementation doing this, but ruby annotations are an accessibility feature that is really common is East-Asian comics).

And there’s rendering things like better .nodef boxes for missing glyphs like the ones Firefox has. Or implementing paint-order for joined scripts, or the more advanced colour font formats. I don’t know yet in which order they will go…

Overall, text is complicated, sure, but it was also kinda fun to do? Like, it has a lot of research, and requires a lot of thinking about edge cases, and I’ll freely admit I was very upset whenever I found another new way for the bidirectional algorithm to make life difficult (though, it seems my code became simpler every time I fixed a right-to-left bug), but at the same time, I have seen a lot of programmers trying to do what I did, and at the research stage they give up, panicking at the size and fiddliness of it all (further fueled by articles like these making the rounds, said article is fully correct btw. We thankfully don’t have to worry about some of the elements, Krita being a painting program and not needing the ability to layout and render thousands of words like a web browser). I am still not sure why I was able to do all this, but if you are in my situation my tips would be:

  • Try to figure out what has priority for your usecase. Krita as a painting program doesn’t need to do subpixel anti-aliasing, because more or less no other graphics program does that, which in turn is because type-setting of text in graphics programs is usually at a larger size/resolution. So I am not going to do that.
  • Limit your scope. There’s a whole bunch of things in the parser or elsewhere that I am flat out ignoring for this particular project. If I had to implement a on-canvas tool in this same patch, or some of the obscurer ways of handling a CSS-value, I too, would go nuts.
  • Do try to test multiple scripts, even if you can’t read them.
  • Likely, someone out there will have tried to solve what you’re trying to solve, and if not, you do not need to be the first person to solve it. This is largely why I spoke against any suggestion to shift away from SVG for text, even though most painting programs don’t mix text layout and vectors: CSS is a very mature standard, and there is tons of discussion by people of all sorts of backgrounds on how to implement something, even if it also has stuff that only makes sense in an historical context.
  • Examples of unsolved problems include, but are not limited to:
    • Using ligatures and kashida to improve the quality of Justification. There’s attempts out there, but the quality is not great, and no one knows what the best possible solution would look like (hell, as far as I can tell there’s even no consensus at which part of the stack it needs to happen).
    • Figuring out breakpoints for languages that have no word-spacers for the computer to recognize as break-points like Thai. There’s some rumours about using dictionaries to recognize the words, but that is too little information: what kind of dictionaries? And do we have to do some processing on those dictionaries as well, like a spelling checker would???
    • Apparently letter-grouping for Devanagari uses different groupings than unicode graphemes, but there’s no documentation on what that entails.
    • Getting the glyphs of joined scripts to merge so it doesn’t give a wrong outline. The big browsers may have their own problems here, but in Krita’s case we rely on qt’s path union operation, which is too crude for text glyphs, so hence why I am going to implement paint-order so artists can specify outlines to be drawn behind the main text, though it will still not solve everything.
    • How are color font glyphs supposed to be stroked, if at all?

And like, it’s very hard, no doubt about that, but it is not impossible.

P.S. Sorry to the Inkscape devs for the bugs I found but did not report: I can’t seem to get my gitlab.com login to work.

Friday, 28 October 2022

 Commit: https://invent.kde.org/qt/qt/qt5/-/commit/17246d90b97ef6ecc05cb225bc576b4fb30ca77a

 

Commercial release announcement: https://www.qt.io/blog/commercial-lts-qt-5.15.7-released 


OpenSource release announcement: https://lists.qt-project.org/pipermail/announce/2022-October/000376.html

 

As usual I want to personally extend my gratitude to the Commercial users of Qt for beta testing Qt 5.15.7 for the rest of us.

 

The Commercial Qt 5.15.7 release introduced one bug that has later been fixed. Thanks to that, our Patchset Collection has been able to incorporate the revert for bug [1]  and the Free Software users will never be affected by it!

Very much later in the day than the usual, I was busy doing things with interlocking brick somehow… Anyway, let’s go for my web review for the week 2022-43.


Microsoft Confirms Server Misconfiguration Led to 65,000+ Companies’ Data Leak

Tags: tech, cloud, microsoft, security, leak

Let’s put all our data in bigger and bigger silos… what could possibly go wrong?

https://thehackernews.com/2022/10/microsoft-confirms-server.html?m=1


Stop writing Twitter threads! - Chez pieq

Tags: tech, twitter, blog

Hear! Hear! Let’s have the blogs back pretty please… I hate those threads.

https://pierre.equoy.fr/blog/posts/2022/10/stop-writing-twitter-threads/


s l o w  r o a d s

Tags: tech, gaming, casual

OK, this is a funny concept for a casual game. I wish it’d be Free Software of course.

https://slowroads.io/


SadServers - Troubleshooting Linux Servers

Tags: tech, linux, production, server

OK, that looks like cool challenges to train your troubleshooting skills.

https://sadservers.com/


Stranger Strings: An exploitable flaw in SQLite | Trail of Bits Blog

Tags: tech, sql, sqlite, security, tests, coverage

Interesting bug in SQLite. In particular look for the conclusion regarding tests and coverage. It’s something I often have to remind people of.

https://blog.trailofbits.com/2022/10/25/sqlite-vulnerability-july-2022-library-api/


Blending Modes | Dan Hollick 🇿🇦

Tags: tech, graphics, blending, gui

Nice summary of the various blending modes you can use in graphics. Well done.

https://typefully.com/DanHollick/blending-modes-KrBa0JP


Programming Portals

Tags: tech, design, command-line, gui, programming

Very interesting musing about the UX divide between GUI and CLI/text and how this could be approached to have both interacting better.

https://maggieappleton.com/programming-portals


Python Design Patterns

Tags: tech, design, programming, python

OK, the writing is sometimes a bit biased in my opinion (didn’t you know Python is superior to any other language?). That being said, this is an interesting resource to get ideas on how the GoF proposed set of design patterns apply in the Python world. I like this kind of “how do things relate” resources.

https://python-patterns.guide/


A Flexible Framework for Effective Pair Programming — Culture (2022)

Tags: tech, pairing, programming, culture

Very thorough article with plenty of tips and ideas on how to run nice pair programming sessions.

https://shopify.engineering/a-flexible-framework-for-effective-pair-programming


Information for decision-makers considering the SAFe framework - Google Docs

Tags: tech, agile, criticism, safe

This feels odd to be hosted on a Google Doc, but this is an interesting list of case studies and opinions around SAFe. I learned a few things, I didn’t realize it’s creation was so disconnected from the pre-existing agile community. It all seems to confirm my opinion that it’s better to stay away from it though. The few organizations I know of which use it are clearly very much in a command and control mode. This is going backwards.

https://docs.google.com/document/d/1EdkoKpURZREBOmArg4aopWTzOhvEPfCgTD-aLNMSTgg/edit


Performance “Seasons” Are Useless — Use Anniversary Reviews Instead - Jacob Kaplan-Moss

Tags: management, hr

As I could experience both, I concur. Anniversary reviews are just much better for everyone involved.

https://jacobian.org/2022/oct/25/against-performance-seasons/


Why you feel uncertain about everything you make

Tags: management, business, feedback

Interesting point. It’s clearly not easy to get proper feedback depending the size of the group we’re reaching out to.

https://vanschneider.com/blog/why-you-feel-uncertain-about-everything-you-make/


What “Work” Looks Like - Jim Nielsen’s Blog

Tags: management, collaborative

Maybe a bit heavy handed in the way it is presented in this piece. Still, constant brainstorming can get in the way of true focus or getting in the zone. This is definitely needed for some problems.

https://blog.jim-nielsen.com/2022/what-work-looks-like/


What’s wrong with medieval pigs in videogames? - Leiden Medievalists Blog

Tags: tech, history, gaming, farming

Very interesting article. The medieval pig is totally not like we imagined, both on how it looked or how it behaved.

https://www.leidenmedievalistsblog.nl/articles/whats-wrong-with-medieval-pigs-in-videogames


Fujimoto’s Five Books are now Public Domain - Origami by Michał Kosmulski

Tags: art, origami, japan

Wow, now that’s a serious body of work about origamis being in the public domain! Rejoice!

https://origami.kosmulski.org/blog/2022-10-23-fujimoto-books-public-domain


Plastic recycling remains a ‘myth’: Greenpeace study

Tags: ecology

The best plastic remains the one which wasn’t produced in the first place. Time for more returnable and reusable containers for a start?

https://phys.org/news/2022-10-plastic-recycling-myth-greenpeace.html



Bye for now!

Sunday, 23 October 2022

Just a small note that Kirigami Addons 0.5 was released yesterday. This update only contains some small cleanups here and there (e.g. moving some implementation details from the public api to the private one).

The package is available on download.kde.org and was signed with my new GPG key

Friday, 21 October 2022

Let’s go for my web review for the week 2022-42.


Stable Diffusion is a really big deal

Tags: tech, ai, machine-learning, ethics

Not much new in this article regarding Stable Diffusion. That being said the section about ethics is spot on. This is the toughest part to grapple with regarding the latest batch of generative AIs. The legal traceability of the training set might end up being required (even though I doubt it will happen).

https://simonwillison.net/2022/Aug/29/stable-diffusion/#ai-vegan


GitHub Copilot investigation · Joseph Saveri Law Firm & Matthew Butterick

Tags: tech, law, copyright, foss, github, copilot, microsoft

Alright, this going to be interesting. Pass me the pop corn. It’s definitely a welcome move in any case.

https://githubcopilotinvestigation.com/


EasyList is in trouble and so are many ad blockers

Tags: tech, foss, community, browser

How a design flaw in some obscure browsers can put a community project to its knees.

https://adguard.com/en/blog/easylist-filter-problem-help.html


Why we’re leaving the cloud

Tags: tech, cloud, business, economics

Hear! Hear! No, moving your infrastructure to managed services doesn’t make sense in all cases. You need to be in the right place in term of complexity and traffic to really benefit from it. It’s less common than you’d think due to the marketing pressure.

https://world.hey.com/dhh/why-we-re-leaving-the-cloud-654b47e0


Feather – Simply beautiful open source icons

Tags: tech, icons, design

Nice little tool to easily produce icons in a cohesive style.

https://feathericons.com/


A simple static site generator

Tags: tech, blog, self-hosting

OK, super tiny and simple. This looks like a nice alternative for the big ones like Jekyll or Hugo.

https://mkws.sh/


A Real World React -> htmx Port

Tags: tech, htmx, html, javascript, frontend, django, webcomponents

Interesting data point about a service moving completely to the htmx and web components approaches. Not all applications are going to see such drastic improvements, that being said the change in team structure alone feels like a very good thing to me (and is more likely to be the constant in such moves).

https://htmx.org/essays/a-real-world-react-to-htmx-port/


Musings on Python Type Hints — samgeo.codes

Tags: tech, python, type-systems, mypy

Interesting examples where the Python type hints are used. This still needs improvements but it’s clearly improving.

https://samgeo.codes/blog/python-types/


Test smarter, not harder - lukeplant.me.uk

Tags: tech, tests, tdd, craftsmanship

Lots of very good points, I’m a proponent of TDD but I strongly agree with this. If it’s painful and not fun, find a way to do it differently. There’s likely a tool or some API you miss. Manage your effort.

https://lukeplant.me.uk/blog/posts/test-smarter-not-harder/


Rust-like traits in C++ | dragly

Tags: tech, programming, c++, rust

Always interesting when a language influence the use of another one. I like this kind of epiphanies.

https://dragly.org/2018/04/21/rust-like-traits-in-cpp/


RAII: Compile-Time Memory Management in C++ and Rust :: The Coded Message

Tags: tech, programming, rust, c++, memory

Very good overview about RAII, ownership, borrowing references. All that comparing C++ and Rust in their ways to handle those concepts. Definitely a must-read even though it’s a bit long.

https://www.thecodedmessage.com/posts/raii/


How Trying New Programming Languages Helped Me Grow as a Software Engineer

Tags: tech, programming, craftsmanship, learning

Definitely this. I regularly try to pick up new languages for this exact reason. Every time it improves the way I use the languages I already knew.

https://cichocinski.dev/blog/trying-new-programming-languages-helped-grow-software-engineer


tdarb.org / Avoiding Featurism

Tags: tech, product-management, project-management, team, complexity

Very important points. This can easily turn a project into a death march with rampant undue complexity. Also the proposed guidelines are simple and seem efficient.

https://tdarb.org/blog/avoid-featurism.html


Wait vs Interrupt Culture | Compass Rose

Tags: culture, conversation, life

That’s a very interesting way to frame it. Two different cultures to drive a conversation, both with their pros and cons. Lots to mull over for me in that short article.

http://benjaminrosshoffman.com/wait-vs-interrupt-culture/


Conway’s Law

Tags: tech, architecture, conway, organization, business

Very good primer on Conway’s Law by Martin Fowler. Definitely recommended, obviously this is just a start and requires diving deeper in the topic.

https://martinfowler.com/bliki/ConwaysLaw.html


Non-Euclidean geometry and games

Tags: tech, gaming, 3d, geometry, mathematics

Nice little article rehashing what it really means to have a non-euclidian geometry since the term has been unfortunately abused lately. Also gives a list of games to experience weird geometries.

https://zenorogue.scribe.rip/non-euclidean-geometry-and-games-fb46989320d4


Sound – Bartosz Ciechanowski

Tags: science, sound

Again a very nice interactive article. This time about sound, very thorough. Reminded me some of the things I learned at school (but then forgot) a long time ago.

https://ciechanow.ski/sound/


Phantom Forests: Why Ambitious Tree Planting Projects Are Failing - Yale E360

Tags: science, nature, ecology

Planting trees to help, sure. Let’s do it properly though, sometimes that means just getting out of the way.

https://e360.yale.edu/features/phantom-forests-tree-planting-climate-change


Barcelona-style “superblocks” could make a surprising number of cities greener and less car-centric

Tags: urbanization, ecology

Interesting research about city planning. Definitely a bigger challenge in the future for larger cities.

https://www.anthropocenemagazine.org/2022/03/barceolona-style-superblocks-a-surprising-number-of-cities-greener/



Bye for now!

Time for another revision of the digiKam Recipes book. This update features a completely revised chapter covering the versioning functionality in digiKam. It now offers a clear explanation of how versioning works in digiKam, which can help you to get the most out of this versatile feature. The Add shell scripts to the Import module chapter has also been revised to include a better practical example of how to use shell scripts with the Import tool. The new Enable and configure tooltips chapter describes how to put the handy tooltip tool to practical use, while the Travel in time using advanced search tip demonstrates how you can use the advanced search feature to find photos from the past.

Thursday, 20 October 2022

Intro & thanks

About a year ago I wrote about my gripes with Firefox not playing nicely with KDE Plasma Activities and how I created an Activity-aware Firefox hack/wrapper. While I was pretty happy with it back then and especially the 0.2 version, since then things have improved quite a bit.

First of all, it seems others found my solution useful as well and even started filing issues and contributing code. I am ever so grateful for that, as I was already at the limits of my shell scripting skills with the 0.2 version and Activity-aware Firefox would have never gotten as good as it is now, without the help of Cristian Le and Jarosław Czarniak!

Version 0.4.1 is now the first version I would consider ready for mass use and if you are also a heavy user of both Plasma’s Activities and Firefox, I would warmly recommend you try it out.

Main changes

So what are the biggest notable changes since my last blog post about it that grew my 30-line “works for me” proof of concept into a much more mature 285-line script?

  • in general it is rewritten to be distro-agnostic and much safer and reliable to use
  • it includes interactive elements
    • dialog (including help) on first launch that assists with starting a new Profile, copying some info from either the default or template Profile, or migrating from the earliest versions (0.1 and 0.2)
    • dialog to clean up Profiles that are left over from deleted Activities
    • desktop notifications
  • dependency check
  • debug mode (activityfirefox +x)
  • names of Firefox Profiles now include the names of the respecfive Plasma Activities

In addition to that, we have equipped the repository to resemble a serious project.

It now includes both a very informativeREADME and a well-structuredCHANGELOG. We are using tags and releases to mark important points in the development. And last, but not least, the repository is REUSE-compliant, so licensing and copyright information is as good as it gets.

Invitation to use & contribute

That said, you are warmly invited to visit Activity-aware Firefox’ GitLab repository, where you can read more about it, install and use it …and of course, help make it even better by contributing code, bug reports or ideas :)

hook out → mmmm, chestnuts

UserBase is a wiki about all things KDE with a goal of presenting our users with helpful and up-to-date information. Sadly, we are some way from achieving this: While KDE developers are moving swiftly forwards producing amazing software our efforts to document this have been stalling.

At the recent Akademy, a week long gathering of KDE community members, we decided to do something about it. It is a big task, however, and we need your help! The team is small, but we hope it will grow and become a vibrant and friendly community.

Join the UserBase Team

If you want to join the effort to get UserBase in shape again, please get in touch. An easy way is to go to the talk page of the team page and introduce yourself. The Wiki Team Page itself is where we plan the task ahead. Currently the plan is very sketchy – feel free to add your ideas.

You can also ping me on IRC (claus_chr in #kde-wiki on Libera Chat) or on Matrix (claus_chr in #kde-www:kde.org), or leave a comment on my UserBase page. Or you can just dive right in: find a page that needs some love and start improving it.

How You Get an Account on UserBase

To edit pages on UserBase you need to make a KDE Identity account. (If you already have an KDE Identity account for some other purpose you don’t need a new account; just reuse the existing one.) Now you can log in to UserBase and start editing.