123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- // Copyright 2022 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "ui/qt/qt_shim.h"
- #include <stdio.h>
- #include <QApplication>
- #include <QFont>
- #include <QIcon>
- #include <QMimeDatabase>
- #include <QMimeType>
- #include <QPainter>
- #include <QPalette>
- #include <QStyle>
- #include <QStyleOptionTitleBar>
- namespace qt {
- namespace {
- bool IsStyleItalic(QFont::Style style) {
- switch (style) {
- case QFont::Style::StyleNormal:
- return false;
- case QFont::Style::StyleItalic:
- // gfx::Font::FontStyle doesn't support oblique, so treat it as italic.
- case QFont::Style::StyleOblique:
- return true;
- }
- }
- FontHinting QtHintingToFontHinting(QFont::HintingPreference hinting) {
- switch (hinting) {
- case QFont::PreferDefaultHinting:
- return FontHinting::kDefault;
- case QFont::PreferNoHinting:
- return FontHinting::kNone;
- case QFont::PreferVerticalHinting:
- // QT treats vertical hinting as "light" for Freetype:
- // https://doc.qt.io/qt-5/qfont.html#HintingPreference-enum
- return FontHinting::kLight;
- case QFont::PreferFullHinting:
- return FontHinting::kFull;
- }
- }
- // Obtain the average color of a gradient.
- SkColor GradientColor(const QGradient& gradient) {
- QGradientStops stops = gradient.stops();
- if (stops.empty())
- return QColorConstants::Transparent.rgba();
- float a = 0;
- float r = 0;
- float g = 0;
- float b = 0;
- for (int i = 0; i < stops.size(); i++) {
- // Determine the extents of this stop. The whole gradient interval is [0,
- // 1], so extend to the endpoint if this is the first or last stop.
- float left_interval =
- i == 0 ? stops[i].first : (stops[i].first - stops[i - 1].first) / 2;
- float right_interval = i == stops.size() - 1
- ? 1 - stops[i].first
- : (stops[i + 1].first - stops[i].first) / 2;
- float length = left_interval + right_interval;
- // alpha() returns a value in [0, 255] and alphaF() returns a value in
- // [0, 1]. The color values are not premultiplied so the RGB channels need
- // to be multiplied by the alpha (in range [0, 1]) before summing. The
- // alpha doesn't need to be multiplied, so we just sum color.alpha() in
- // range [0, 255] directly.
- const QColor& color = stops[i].second;
- a += color.alpha() * length;
- r += color.alphaF() * color.red() * length;
- g += color.alphaF() * color.green() * length;
- b += color.alphaF() * color.blue() * length;
- }
- return qRgba(r, g, b, a);
- }
- // Obtain the average color of a texture.
- SkColor TextureColor(QImage image) {
- size_t size = image.width() * image.height();
- if (!size)
- return QColorConstants::Transparent.rgba();
- if (image.format() != QImage::Format_ARGB32_Premultiplied)
- image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
- size_t a = 0;
- size_t r = 0;
- size_t g = 0;
- size_t b = 0;
- const auto* pixels = reinterpret_cast<QRgb*>(image.bits());
- for (size_t i = 0; i < size; i++) {
- auto color = QColor::fromRgba(pixels[i]);
- a += color.alpha();
- r += color.red();
- g += color.green();
- b += color.blue();
- }
- return qRgba(r / size, g / size, b / size, a / size);
- }
- SkColor BrushColor(const QBrush& brush) {
- QColor color = brush.color();
- auto alpha_blend = [&](uint8_t alpha) {
- QColor blended = color;
- blended.setAlpha(blended.alpha() * alpha / 255);
- return blended.rgba();
- };
- switch (brush.style()) {
- case Qt::SolidPattern:
- return alpha_blend(0xFF);
- case Qt::Dense1Pattern:
- return alpha_blend(0xE0);
- case Qt::Dense2Pattern:
- return alpha_blend(0xC0);
- case Qt::Dense3Pattern:
- return alpha_blend(0xA0);
- case Qt::Dense4Pattern:
- return alpha_blend(0x80);
- case Qt::Dense5Pattern:
- return alpha_blend(0x60);
- case Qt::Dense6Pattern:
- return alpha_blend(0x40);
- case Qt::Dense7Pattern:
- return alpha_blend(0x20);
- case Qt::NoBrush:
- return alpha_blend(0x00);
- case Qt::HorPattern:
- case Qt::VerPattern:
- return alpha_blend(0x20);
- case Qt::CrossPattern:
- return alpha_blend(0x40);
- case Qt::BDiagPattern:
- case Qt::FDiagPattern:
- return alpha_blend(0x20);
- case Qt::DiagCrossPattern:
- return alpha_blend(0x40);
- case Qt::LinearGradientPattern:
- case Qt::RadialGradientPattern:
- case Qt::ConicalGradientPattern:
- return GradientColor(*brush.gradient());
- case Qt::TexturePattern:
- return TextureColor(brush.textureImage());
- }
- }
- QPalette::ColorRole ColorTypeToColorRole(ColorType type) {
- switch (type) {
- case ColorType::kWindowBg:
- return QPalette::Window;
- case ColorType::kWindowFg:
- return QPalette::WindowText;
- case ColorType::kHighlightBg:
- return QPalette::Highlight;
- case ColorType::kHighlightFg:
- return QPalette::HighlightedText;
- case ColorType::kEntryBg:
- return QPalette::Base;
- case ColorType::kEntryFg:
- return QPalette::Text;
- case ColorType::kButtonBg:
- return QPalette::Button;
- case ColorType::kButtonFg:
- return QPalette::ButtonText;
- case ColorType::kLight:
- return QPalette::Light;
- case ColorType::kMidlight:
- return QPalette::Midlight;
- case ColorType::kMidground:
- return QPalette::Mid;
- case ColorType::kDark:
- return QPalette::Dark;
- case ColorType::kShadow:
- return QPalette::Shadow;
- }
- }
- QPalette::ColorGroup ColorStateToColorGroup(ColorState state) {
- switch (state) {
- case ColorState::kNormal:
- return QPalette::Normal;
- case ColorState::kDisabled:
- return QPalette::Disabled;
- case ColorState::kInactive:
- return QPalette::Inactive;
- }
- }
- } // namespace
- QtShim::QtShim(QtInterface::Delegate* delegate, int* argc, char** argv)
- : delegate_(delegate), app_(*argc, argv) {
- connect(&app_, SIGNAL(fontChanged(const QFont&)), this,
- SLOT(FontChanged(const QFont&)));
- connect(&app_, SIGNAL(paletteChanged(const QPalette&)), this,
- SLOT(PaletteChanged(const QPalette&)));
- }
- QtShim::~QtShim() = default;
- double QtShim::GetScaleFactor() const {
- return app_.devicePixelRatio();
- }
- FontRenderParams QtShim::GetFontRenderParams() const {
- QFont font = app_.font();
- auto style = font.styleStrategy();
- return {
- .antialiasing = !(style & QFont::StyleStrategy::NoAntialias),
- .use_bitmaps = !!(style & QFont::StyleStrategy::PreferBitmap),
- .hinting = QtHintingToFontHinting(font.hintingPreference()),
- };
- }
- FontDescription QtShim::GetFontDescription() const {
- QFont font = app_.font();
- return {
- .family = String(font.family().toStdString().c_str()),
- .size_pixels = font.pixelSize(),
- .size_points = font.pointSize(),
- .is_italic = IsStyleItalic(font.style()),
- .weight = font.weight(),
- };
- }
- Image QtShim::GetIconForContentType(const String& content_type,
- int size) const {
- QMimeDatabase db;
- for (const char* mime : {content_type.c_str(), "application/octet-stream"}) {
- auto mt = db.mimeTypeForName(mime);
- for (const auto& name : {mt.iconName(), mt.genericIconName()}) {
- auto icon = QIcon::fromTheme(name);
- auto pixmap = icon.pixmap(size);
- auto image = pixmap.toImage();
- if (image.format() != QImage::Format_ARGB32_Premultiplied)
- image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
- if (auto bytes = image.sizeInBytes()) {
- return {image.width(), image.height(),
- static_cast<float>(image.devicePixelRatio()),
- Buffer(image.bits(), bytes)};
- }
- }
- }
- return {};
- }
- SkColor QtShim::GetColor(ColorType role, ColorState state) const {
- return BrushColor(app_.palette().brush(ColorStateToColorGroup(state),
- ColorTypeToColorRole(role)));
- }
- SkColor QtShim::GetFrameColor(ColorState state, bool use_custom_frame) const {
- constexpr int kSampleSize = 32;
- return TextureColor(DrawHeaderImpl(kSampleSize, kSampleSize,
- GetColor(ColorType::kWindowBg, state),
- state, use_custom_frame));
- }
- int QtShim::GetCursorBlinkIntervalMs() const {
- return app_.cursorFlashTime();
- }
- int QtShim::GetAnimationDurationMs() const {
- return app_.style()->styleHint(QStyle::SH_Widget_Animation_Duration);
- }
- void QtShim::FontChanged(const QFont& font) {
- delegate_->FontChanged();
- }
- void QtShim::PaletteChanged(const QPalette& palette) {
- delegate_->ThemeChanged();
- }
- Image QtShim::DrawHeader(int width,
- int height,
- SkColor default_color,
- ColorState state,
- bool use_custom_frame) const {
- QImage image =
- DrawHeaderImpl(width, height, default_color, state, use_custom_frame);
- return {width, height, 1.0f, Buffer(image.bits(), image.sizeInBytes())};
- }
- QImage QtShim::DrawHeaderImpl(int width,
- int height,
- SkColor default_color,
- ColorState state,
- bool use_custom_frame) const {
- QImage image(width, height, QImage::Format_ARGB32_Premultiplied);
- image.fill(default_color);
- QPainter painter(&image);
- if (use_custom_frame) {
- // Chrome renders it's own window border, so clip the border out by
- // rendering the titlebar larger than the image.
- constexpr int kBorderWidth = 5;
- QStyleOptionTitleBar opt;
- opt.rect = QRect(-kBorderWidth, -kBorderWidth, width + 2 * kBorderWidth,
- height + 2 * kBorderWidth);
- if (state == ColorState::kNormal)
- opt.titleBarState = QStyle::State_Active;
- app_.style()->drawComplexControl(QStyle::CC_TitleBar, &opt, &painter,
- nullptr);
- } else {
- painter.fillRect(
- 0, 0, width, height,
- app_.palette().brush(ColorStateToColorGroup(state), QPalette::Window));
- }
- return image;
- }
- } // namespace qt
- qt::QtInterface* CreateQtInterface(qt::QtInterface::Delegate* delegate,
- int* argc,
- char** argv) {
- return new qt::QtShim(delegate, argc, argv);
- }
|