Skip to content

Framework needs to be aware of physical pixels #116278

@knopp

Description

@knopp

I'm filing this as separate from #111302, because I don't believe it is necessarily canvas related. Trying to fix this when painting to canvas is too late.

Framework currently acts as if it is rendering to surface with infinite resolution. However in practice this is not the case and on many (mostly desktop, but also mobile) devices this results in degraded experience. Below are comparison screenshot of simple screen with two rectangles having 1px (logical) border with various DPI scalings.

HTML
<html>
<head></head>
<body style="background-color: black; font-family: sans-serif;">
    <div style="margin-left: 20; margin-top: 20; border: 1px solid yellow; display: inline-flex; width: 64px; height: 44px; box-sizing: border-box; background-color: rgba(255, 166, 0, 0.428); align-items: center; justify-content: center;">
        <div style="display: inline-block; border: 1px solid yellow; padding: 5px; color: white;">
            Hello
        </div>
    </div>
</body>
</html>
Flutter
import 'package:flutter/material.dart';

void main() {
  runApp(
    DefaultTextStyle(
      style: const TextStyle(
        fontSize: 11,
        color: Colors.white,
        decoration: TextDecoration.none,
        fontWeight: FontWeight.normal,
      ),
      child: Align(
        alignment: Alignment.topLeft,
        child: Padding(
          padding: const EdgeInsets.only(left: 20, top: 20),
          child: SizedBox(
            width: 64,
            height: 44,
            child: Container(
              decoration: BoxDecoration(
                  color: const Color.fromRGBO(255, 166, 0, 0.428),
                  border: Border.all(color: Colors.yellow, width: 1)),
              child: Center(
                child: Container(
                  decoration: BoxDecoration(
                      border: Border.all(color: Colors.yellow, width: 1)),
                  padding: const EdgeInsets.all(5),
                  // This is to make sure text has even height and can be properly shown
                  // at least on 1x scaling
                  child: Padding(
                    padding: const EdgeInsets.only(bottom: 1.0),
                    child: const Text(
                      'Hello',
                      textDirection: TextDirection.ltr,
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    ),
  );
}

Comparison of Flutter (left) vs Web Browser (right)

100% scaling

100

Here the borders are identical (though did need to massage the Flutter code with additional padding so that text had even height and could be centered vertically without blur; see the very last screenshot).

125% scaling

125

Web image is crisp (border is still 1 physical pixel), Flutter borders are blurred.

150% scaling

150

Web image still has one physical pixel border, Flutter blurry. With 175% scaling, the border is on web still 1 physical pixel, though in some applications (WinUI) this is where 1 logical pixel turns into two physical pixels.

200% scaling

200

Here Flutter and Web finally look identical.

Bonus image: Flutter at 100%, without extra 1px padding below the text:

100-blurry

Ideally, unless there is extra transform in hierarchy (i.e. scale on rotate), all layers that engine receive should be already properly pixel aligned.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions