Skip to content

CefSettings.ColorType: alpha >= 0x80 sign-extends into a negative long, not the intended unsigned ARGB value #8

Description

@Thrameos

Summary

CefSettings.ColorType's packing constructor computes the ARGB value entirely in
32-bit int arithmetic, then relies on implicit widening to store it into the
long color_value field:

public ColorType(int alpha, int red, int green, int blue) {
    color_value = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
}

When alpha >= 0x80, (alpha << 24) sets the sign bit of the intermediate int
result, making the whole packed expression a negative int. Java's implicit
int -> long widening then sign-extends that negative value, so color_value
ends up with all of the long's upper 32 bits set to 1 -- not the plain
unsigned 32-bit ARGB value a caller would reasonably expect from a field typed
long specifically to represent one.

Repro

CefSettings settings = new CefSettings();
CefSettings.ColorType color = settings.new ColorType(0xFF, 0x11, 0x22, 0x33);
color.getColor(); // returns 0xFFFFFFFFFF112233L (-16772813), not 0x00000000FF112233L

Low alpha values (< 0x80) are unaffected -- e.g. new ColorType(0x7F, 0x11, 0x22, 0x33)
correctly returns 0x7F112233L.

Impact

Any caller comparing getColor() against an expected unsigned ARGB long constant,
or otherwise treating the field as an unsigned 32-bit color value (as the class's
own Javadoc describes: "32-bit ARGB color value, not premultiplied"), will get
surprising results whenever alpha is >= 0x80 -- which includes the common case of a
fully-opaque color (alpha = 0xFF).

Suggested fix

Mask to 32 bits (or build the value with long-typed intermediate arithmetic) before
assigning to color_value, e.g.:

color_value = ((long) alpha << 24 | (long) red << 16 | (long) green << 8 | blue) & 0xFFFFFFFFL;

Found via

Writing CefSettingsTest.java (new unit tests, coverage-expansion effort tracked in #5)
-- see colorTypeHighAlphaSignExtends(), which documents the current (buggy) behavior
with an explanatory comment rather than silently masking it.

Activity

  1. Thrameos commented on Aug 31, 2026

    @Thrameos
    OwnerAuthor

    Fixed. CefSettings.ColorType's constructor now packs in long-typed arithmetic and masks to 32 bits, exactly as suggested:

    color_value = ((long) alpha << 24 | (long) red << 16 | (long) green << 8 | blue) & 0xFFFFFFFFL;

    Verified: new ColorType(0xFF, 0x11, 0x22, 0x33).getColor() now returns 0xFF112233L instead of the sign-extended 0xFFFFFFFFFF112233L. Updated CefSettingsTest.colorTypeHighAlphaSignExtends() (renamed to colorTypeHighAlphaDoesNotSignExtend()) to assert the correct value as a regression test instead of documenting the bug. Full suite for this class: 6/6 passing.

  2. added 3 commits that reference this issue on Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions