GithubHelp home page GithubHelp logo

mjakeman / text-engine Goto Github PK

View Code? Open in Web Editor NEW
20.0 1.0 2.0 440 KB

A lightweight rich text framework for GTK

License: Other

Meson 1.46% C 98.50% CSS 0.04%
c document gtk rich-text rich-text-editor

text-engine's Introduction

Text Engine

Text Engine is a rich-text editing framework for GTK 4. The primary user of this library is bluetype but it can be used wherever rich text display and editing is needed.

The text engine demo displaying sample rich text

Status

The library is under heavy development and generally not suitable for use in applications. For packagers, note that Extension Manager builds against version 0.1 of this library.

Matrix

Development of text-engine and bluetype takes place on matrix.

Join #bluetype to chat about the project or if you would like to get involved. Come say hello!

Licence

Text Engine is dual-licensed under the Mozilla Public License 2.0 and the GNU Lesser General Public License 2.1 (or any later version), at your option. You may choose to use the library under either of the aforementioned licenses, or both. See COPYING for more information.

text-engine's People

Contributors

mjakeman avatar oscfdezdz avatar jbicha avatar

Stargazers

Pascal Garber avatar Tom avatar Diamond avatar zjzhang avatar Kinten Le avatar Garfield Linden avatar Alexander Barbosa avatar Jhonson Ozuna Mejia avatar Ki Rill avatar Kevin Chen avatar Wang Chao avatar  avatar Diego Iván M.E avatar Colin Kiama avatar Schmidt avatar Ali Galal avatar Different55 avatar  avatar Sam Dolt avatar Benjamin Quinn avatar

Watchers

 avatar

Forkers

jbicha oscfdezdz

text-engine's Issues

Unit Tests

Write a comprehensive test suite to ensure document layout, model, and formats do not break.

Fully implement rendering model

The text-engine rendering model is a very simplified version of most major browsers:

image

It consists of five individual trees:

  • Model: A hierarchical description of the document (basically HTML with fewer elements)
  • Format: A cascade of styles (CSS circa v2?)
  • Style: Matching model elements with their relevant styles to construct an efficient representation of the fully formatted document
  • Layout: Recursively determines how large elements want to be, what size they should be (in relation to the available space), etc. The layout module is designed to be hotswappable by the end user, so they can customise text-engine to their liking (the other models are likely to be internal only). Different layouts can be used to achieve things like reflowable vs paged layouts.
  • Display: Convert layout nodes to platform specific drawing commands. Also responsible for things like occlusion culling, etc. GTK code may exist ONLY in this stage. This would also let us support e.g. Qt, GTK3 if someone shows up with patches.

Each tree is cached and only updates relevant parts whenever a previous tree is invalidated (see #11). Style nodes and layout nodes will be attached together; there is a one-to-one relationship between them. Style nodes wrap model nodes and index format nodes. I might simplify this by dropping style altogether and make model nodes refer to format directly.

Once implemented, it should be fully documented.

Investigate a port to Rust

Yes, really...

Unfortunately unicode text handling is rather painful in C. Additionally, being glib-based causes all sorts of problems for embedding due to the LGPL forbidding static linking.

Investigate a rewrite of the library in Rust, using pluggable backends for font metrics and a custom text layout system (we handling line breaking, justification, etc instead of delegating to Pango).

This will result in:

  • Much better 'correctness'
  • Improved performance
  • More portability

I've started work on this here: https://github.com/mjakeman/text-engine/tree/rust

The engine will be designed for embedding and have a pure C API. This should support out-of-tree 'ports' e.g. for SwiftUI and/or Android.

Implement basic formatting

We want the ability to change the size and style of text. This means support for font weight, styles (italic, small caps, etc), colour, size.

There should be some way of cascading styles, for example when putting a heading inside a block quote.

  • Bold/Italic/Underline
  • Font size
  • Headings
  • Colours
  • Cascading Style

New release?

Could you do a new release of text-engine? There are commits from 2022.

I noticed because #36 fixes some new compiler errors seen with gcc-14 which some distros have switched to now.

Implement lists

Add lists for the Text Engine MVP (v0.2)

  • Ordered and unordered lists
  • Paragraph decorations
  • Indentation

Add epub reader demo

Once #23 is finished, we'll have enough in-place to display most simple epub2 books (minus images). Could add an epub reader demo to show off the bells and whistles.

New release request

Hi, @mjakeman I'd like to package this for debian but I see you've changed the licence after the v0.1.0 release. So would you mind making a new release so I can package it with just the LGPL?

I've also packaged extension-manager and blueprint-compiler for debian too, in case you didn't know. so :wave

Formalise character positioning

aka 'The wonderful wild world of word wrapping' :/

Introduction

The way we currently handle cursor positions is a mess. For each paragraph, it is comprised of several 'runs', with each run being a block of contiguously formatted text. Text is indexed on a per-paragraph basis.

Character movement is handled by the TextEditor class, while home/end movement is handled by the TextDisplay class. This is because at present a TextDocument is a semantic description of the document, paired with a TextLayout to create the actual formatted document. TextEditor operates directly on the semantic document (as it should, at least for now).

Traversal between paragraphs is not a problem as each paragraph can be considered a 'self-contained' block, so going from the end of one paragraph to the start of another paragraph is one movement backwards/forwards.

The problem arising when dealing with paragraphs that span multiple lines, and particularly when words themselves are split instead of wrapped. When we use home/end, where should the cursor go?

Google Docs:

Paragraph wraps, word is not split:

The space is used to correctly handle traversal between the end of the first line and the start of the second. No special case needed.

Screen.Recording.2022-08-24.at.5.54.53.PM.mov

Paragraph wraps, word is split:

Docs appears to use a 'before character' approach in that the caret position is determined by the following character. This is particularly nice because pressing end takes you to the final index position on the line, belonging to the final character on the line (i.e. the space or tab). For the final line in the paragraph however, there is no break and so we need to account for the extra index.

Screen.Recording.2022-08-24.at.6.07.59.PM.mov

Text Engine:

Paragraph wraps, word is not split:

Normal navigation works, but the current state of home/end dumps the cursor on the line after. This is probably fixable by choosing the index preceding the final character on the line.

Screen.Recording.2022-08-24.at.6.00.54.PM.mov

Paragraph wraps, word is split:

Again this works similarly to Google Docs, however we have the additional '-' character inserted by Pango when word wrapping. We could probably disable this? The issue here which makes it look much worse than it is stems from 'end' using the character after, rather than the character before. This makes it appear like two characters are being skipped. Switching to a character before system puts us on par with Google Docs and is probably the best path forward:

Screen.Recording.2022-08-24.at.6.03.44.PM.mov

Again we need to count for the additional index on the final line, as there is no 'break' character.

Conclusions

We should:

  • Follow the Google Docs model of character positioning within paragraphs
  • Make Home and End to use the first index and last index on a given line
  • Refactor movement into a new TextTraversal auxiliary object?
    • Alternatively make TextEditor layout-aware (not too happy with the idea)
  • Unit test everything

Better unicode handling

As of #32, we use unicode character offsets exclusively for navigation.

Character offsets refer to unicode code points, however some characters like emoji are composite and use multiple code points. Let's find a way to navigate by grapheme (group of code points) rather than each code point.

Announcements

Follow this issue for notifications of a new release or string freeze.

Release Checklist

  • Bump version
  • Bump soname
  • Write release notes
  • Run test suite
  • Tag release

'-Wincompatible-pointer-types' diagnostics cause build failure with GCC 14

Several files' compilation will trigger -Wincompatible-pointer-types diagnostics. This will prevent the project from being successfully built on Fedora 40 and other GNU/Linux distributions that use GCC 14 because, on GCC 14, -Wincompatible-pointer-types is treated as an error rather than a warning.

Steps to reproduce:

  1. Clone this repository and enter the directory that contains the clone.
  2. If gcc --version reports GCC 14 or above, then run meson setup build;
    Otherwise, run CFLAGS="-Werror=incompatible-pointer-types" meson setup build.
  3. Run meson compile -C build.

build.log

Widget should have 'display-only' mode

Add a distinction between editable and non-editable text widgets

When used in display-only mode, see if we can disable or remove the editor logic to improve performance somewhat.

We'll need this for porting Extension Manager to 0.2.

Rework how paragraph breaks are handled

There's a very noticeable bug with the current implementation of paragraph breaks where the cursor cannot be placed on the final index of a paragraph using the mouse or up/down navigation. It can however be done using home/end.

This is due to Pango's internal handling of paragraphs, but isn't something we can easily work around. It might be an idea to use an invisible paragraph break character (I'm sure there's something in unicode) and drop our special casing altogether.

Invalidation and Caching

text-engine uses multiple mutable trees in order to store semantic, style, layout, and render states.

The current pipeline (without a style module) looks as follows:

Model --> Layout --> Render

At present, we recreate the entire layout tree each time a draw is queued. Instead, we should cache the layout tree between redraws. Whenever a change is made to the model, the changed element should be marked as dirty (full recalculation) and all parent elements should be marked as having dirty descendants (partial recalculation).

The layout object watches for changes to the root element and triggers a partial recalculation whenever the root element is either marked dirty or has dirty descendants. Layout recalculations can be done in parallel, as we assume a normal flow for the document (this may change if floating images are supported). If there are more than N recalculations in a frame, we should mark the entire tree as dirty.

Something to avoid is recalculating layout every time the cursor and/or selection changes. This ties in with needing to support Home/End keyboard shortcuts on a per-line basis, as the length of a line is determined by the layout process rather than the document model itself. We'll need some way of moving from Model -> Layout efficiently in order to retrieve line layout data.

Refactor cursor movement

Cursor movement is currently split between editor.c and display.c which is very undesirable. Movement should be handled at a single location, preferably at a level just above layout - it is layout dependent.

The cursor and selection should be separated from the general idea of 'marks' (i.e. cursor/selection is a mark, but not all marks are cursors). We'll also want some way to index text without using marks, in the case of temporary or read only access to the document model.

Widgets and bitmap rendering

Implement 'replaceable' items where the actual drawing (and possibly layout) is done externally. This allows for images and custom controls e.g. image handles, cropping, etc.

Implement images

The next step in reaching the text engine MVP (version 0.2) is allowing for images to be inlined within the view and interacted with using the caret.

The user should be able to:

  • Inline images within a paragraph, such that it changes the line height
  • Insert images as a block element (i.e. between two paragraphs)
  • Select, delete, and modify images using the caret
    • The image should be treated as a one-character-wide object within the model
  • Set image size to either be fixed or to fill available space
  • Float images to the left or right based on a given anchor point
  • Give images alt-text for accessibility purposes (and more generally, implement a11y across the engine)

Not all of this will be available in 0.2 but should be done pre-1.0

  • Inline non-text elements
  • Line breaking
  • Loading and rendering bitmaps
  • Floats
  • Alt-text

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.