Apply style rule
This commit is contained in:
@@ -25,10 +25,8 @@ namespace fs = filesystem;
|
||||
|
||||
namespace dn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
optional<string>
|
||||
static optional<string>
|
||||
edid_md5_from_bytes(const vector<unsigned char> &edid)
|
||||
{
|
||||
if (edid.empty())
|
||||
@@ -38,7 +36,7 @@ edid_md5_from_bytes(const vector<unsigned char> &edid)
|
||||
return md5 ? optional<string>(md5) : nullopt;
|
||||
}
|
||||
|
||||
optional<string>
|
||||
static optional<string>
|
||||
edid_md5_for_connector(const string &connector)
|
||||
{
|
||||
error_code error;
|
||||
@@ -60,7 +58,7 @@ edid_md5_for_connector(const string &connector)
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
vector<unsigned char>
|
||||
static vector<unsigned char>
|
||||
profile_bytes(cmsHPROFILE profile)
|
||||
{
|
||||
cmsUInt32Number size = 0;
|
||||
@@ -73,7 +71,7 @@ profile_bytes(cmsHPROFILE profile)
|
||||
return bytes;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
display_device(CdDevice *device)
|
||||
{
|
||||
if (!device)
|
||||
@@ -82,7 +80,7 @@ display_device(CdDevice *device)
|
||||
return kind == CD_DEVICE_KIND_UNKNOWN || kind == CD_DEVICE_KIND_DISPLAY;
|
||||
}
|
||||
|
||||
DisplayProfile
|
||||
static DisplayProfile
|
||||
load_from_client(CdClient *client, const QScreen *screen)
|
||||
{
|
||||
DisplayProfile result;
|
||||
@@ -172,6 +170,9 @@ load_from_client(CdClient *client, const QScreen *screen)
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct ColordSource final : DisplayProfileSource {
|
||||
CdClient *client = nullptr;
|
||||
guint name_watch = 0;
|
||||
@@ -187,7 +188,9 @@ struct ColordSource final : DisplayProfileSource {
|
||||
void connect_async();
|
||||
};
|
||||
|
||||
void
|
||||
} // namespace
|
||||
|
||||
static void
|
||||
on_device(CdClient *, CdDevice *device, gpointer data)
|
||||
{
|
||||
auto *src = static_cast<ColordSource *>(data);
|
||||
@@ -196,19 +199,19 @@ on_device(CdClient *, CdDevice *device, gpointer data)
|
||||
src->notify();
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
on_changed(CdClient *, gpointer data)
|
||||
{
|
||||
static_cast<ColordSource *>(data)->notify();
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
on_profile(CdClient *, CdProfile *, gpointer data)
|
||||
{
|
||||
static_cast<ColordSource *>(data)->notify();
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
on_connect_ready(GObject *source, GAsyncResult *res, gpointer data)
|
||||
{
|
||||
auto *src = static_cast<ColordSource *>(data);
|
||||
@@ -221,7 +224,7 @@ on_connect_ready(GObject *source, GAsyncResult *res, gpointer data)
|
||||
src->notify();
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
on_name_appeared(GDBusConnection *, const gchar *, const gchar *, gpointer data)
|
||||
{
|
||||
auto *src = static_cast<ColordSource *>(data);
|
||||
@@ -230,7 +233,7 @@ on_name_appeared(GDBusConnection *, const gchar *, const gchar *, gpointer data)
|
||||
src->connect_async();
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
on_name_vanished(GDBusConnection *, const gchar *, gpointer)
|
||||
{
|
||||
}
|
||||
@@ -306,8 +309,6 @@ ColordSource::load(QScreen *screen)
|
||||
return load_from_client(this->client, screen);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
unique_ptr<DisplayProfileSource>
|
||||
make_display_profile_source()
|
||||
{
|
||||
|
||||
@@ -21,10 +21,8 @@ using namespace std;
|
||||
|
||||
namespace dn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
DisplayProfile
|
||||
static DisplayProfile
|
||||
load_display_profile(QScreen *screen)
|
||||
{
|
||||
DisplayProfile result;
|
||||
@@ -58,6 +56,9 @@ load_display_profile(QScreen *screen)
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct CocoaSource final : DisplayProfileSource {
|
||||
function<void()> on_change;
|
||||
id observer = nil;
|
||||
@@ -70,6 +71,8 @@ struct CocoaSource final : DisplayProfileSource {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
CocoaSource::~CocoaSource()
|
||||
{
|
||||
if (!this->observer)
|
||||
@@ -93,7 +96,6 @@ CocoaSource::start(function<void()> fn)
|
||||
}] retain];
|
||||
}
|
||||
|
||||
} // namespace
|
||||
unique_ptr<DisplayProfileSource>
|
||||
make_display_profile_source()
|
||||
{
|
||||
|
||||
@@ -25,8 +25,6 @@ using namespace std;
|
||||
|
||||
namespace dn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
// Monitor class GUID {4d36e96e-e325-11ce-bfc1-08002be10318}
|
||||
constexpr wchar_t kSystemClass[] =
|
||||
@@ -38,7 +36,7 @@ constexpr wchar_t kUserLeaf[] =
|
||||
constexpr wchar_t kUserParent[] =
|
||||
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\ICM";
|
||||
|
||||
DisplayProfile
|
||||
static DisplayProfile
|
||||
load_display_profile(QScreen *screen)
|
||||
{
|
||||
DisplayProfile result;
|
||||
@@ -80,6 +78,9 @@ load_display_profile(QScreen *screen)
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Watch {
|
||||
HKEY key = nullptr;
|
||||
HANDLE event = nullptr;
|
||||
@@ -94,6 +95,8 @@ struct Watch {
|
||||
bool arm();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void
|
||||
Watch::close()
|
||||
{
|
||||
@@ -129,6 +132,9 @@ Watch::arm()
|
||||
this->event, TRUE) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct WcsSource final : DisplayProfileSource {
|
||||
function<void()> on_change;
|
||||
Watch system;
|
||||
@@ -139,6 +145,8 @@ struct WcsSource final : DisplayProfileSource {
|
||||
bool bind(Watch &watch, HKEY root, const wchar_t *path);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
bool
|
||||
WcsSource::bind(Watch &watch, HKEY root, const wchar_t *path)
|
||||
{
|
||||
@@ -176,7 +184,6 @@ WcsSource::load(QScreen *screen)
|
||||
return load_display_profile(screen);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
unique_ptr<DisplayProfileSource>
|
||||
make_display_profile_source()
|
||||
{
|
||||
|
||||
+3
-7
@@ -30,15 +30,13 @@ using namespace std;
|
||||
|
||||
namespace dn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
// One event-loop watch on an dawn::ipc::Waitable. Qt watches sockets on Unix
|
||||
// and overlapped completion events on Windows; nothing below cares which.
|
||||
#ifdef Q_OS_WIN
|
||||
using Watch = QWinEventNotifier;
|
||||
|
||||
Watch *
|
||||
static Watch *
|
||||
make_watch(dawn::ipc::Waitable w, bool, QObject *parent)
|
||||
{
|
||||
return new QWinEventNotifier((Qt::HANDLE) w, parent);
|
||||
@@ -46,7 +44,7 @@ make_watch(dawn::ipc::Waitable w, bool, QObject *parent)
|
||||
#else
|
||||
using Watch = QSocketNotifier;
|
||||
|
||||
Watch *
|
||||
static Watch *
|
||||
make_watch(dawn::ipc::Waitable w, bool write, QObject *parent)
|
||||
{
|
||||
return new QSocketNotifier(qintptr(w),
|
||||
@@ -54,7 +52,7 @@ make_watch(dawn::ipc::Waitable w, bool write, QObject *parent)
|
||||
}
|
||||
#endif
|
||||
|
||||
dawn::ipc::instance::ErrorCode
|
||||
static dawn::ipc::instance::ErrorCode
|
||||
map_open_error(OpenResult r)
|
||||
{
|
||||
switch (r) {
|
||||
@@ -71,8 +69,6 @@ map_open_error(OpenResult r)
|
||||
return dawn::ipc::instance::ErrorCode::Internal;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct InstanceHost::Impl {
|
||||
Impl(dawn::ipc::Listener listener, App &app, const QString &session,
|
||||
InstanceHost *host);
|
||||
|
||||
+38
-37
@@ -145,6 +145,8 @@ struct Spec {
|
||||
Action action;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
constexpr Spec kItems[] = {
|
||||
{Kind::Icon, Slot::Left, Action::Sidebar},
|
||||
{Kind::Icon, Slot::Left, Action::Back},
|
||||
@@ -178,6 +180,9 @@ constexpr Spec kItems[] = {
|
||||
{Kind::Icon, Slot::Right, Action::Fullscreen},
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct ThumbJob {
|
||||
uint64_t gen = 0;
|
||||
Thumbnailer::Priority priority = Thumbnailer::Priority::Dimensions;
|
||||
@@ -304,8 +309,7 @@ is_image_filename(const QString &name)
|
||||
}
|
||||
|
||||
static shared_ptr<dawn::Profile>
|
||||
profile_from_icc(
|
||||
dawn::Cmm &cmm, const shared_ptr<const vector<uint8_t>> &icc)
|
||||
profile_from_icc(dawn::Cmm &cmm, const shared_ptr<const vector<uint8_t>> &icc)
|
||||
{
|
||||
if (icc && !icc->empty()) {
|
||||
if (auto profile = cmm.get_profile(*icc))
|
||||
@@ -361,8 +365,8 @@ static void
|
||||
thumb_dest(const Browser &b, uint32_t gw, uint32_t gh, uint32_t *out_w,
|
||||
uint32_t *out_h)
|
||||
{
|
||||
thumb_dest_params(gw, gh, b.thumb_size_, b.kit_.dpr_, thumb_atlas_max(b),
|
||||
out_w, out_h);
|
||||
thumb_dest_params(
|
||||
gw, gh, b.thumb_size_, b.kit_.dpr_, thumb_atlas_max(b), out_w, out_h);
|
||||
}
|
||||
|
||||
static size_t
|
||||
@@ -416,8 +420,8 @@ caption_name(const string &name)
|
||||
static float
|
||||
row_h(const Browser &b)
|
||||
{
|
||||
return float(b.kit_.px(float(b.thumb_size_)) + 2 * chrome(b.kit_) +
|
||||
label_h(b));
|
||||
return float(
|
||||
b.kit_.px(float(b.thumb_size_)) + 2 * chrome(b.kit_) + label_h(b));
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -576,8 +580,8 @@ make_thumb(shared_ptr<dawn::Cmm> cmm, const ThumbJob &job)
|
||||
const int tier = thumbnail_tier_for_height(
|
||||
max(1, int(ceil(double(job.thumb_size) * double(job.dpr)))));
|
||||
shared_ptr<dawn::Profile> screen = profile_from_icc(*cmm, job.screen_icc);
|
||||
const ThumbnailSource source = thumbnail_source(
|
||||
QString::fromStdString(job.path), job.mtime, job.size);
|
||||
const ThumbnailSource source =
|
||||
thumbnail_source(QString::fromStdString(job.path), job.mtime, job.size);
|
||||
if (job.pending) {
|
||||
if (const ThumbnailTierPixels *pixels = job.pending->find(tier)) {
|
||||
result.ram = *pixels->pixels;
|
||||
@@ -630,8 +634,7 @@ make_thumb(shared_ptr<dawn::Cmm> cmm, const ThumbJob &job)
|
||||
dawn::OpenContext ctx;
|
||||
ctx.uri = job.path;
|
||||
ctx.cmm = cmm;
|
||||
ctx.screen_profile =
|
||||
job.cacheable ? cmm->get_profile_display_p3() : screen;
|
||||
ctx.screen_profile = job.cacheable ? cmm->get_profile_display_p3() : screen;
|
||||
ctx.first_frame_only = true;
|
||||
ctx.screen_dpi = 96;
|
||||
|
||||
@@ -650,8 +653,8 @@ make_thumb(shared_ptr<dawn::Cmm> cmm, const ThumbJob &job)
|
||||
thumb_dest_params(result.geometry_w, result.geometry_h, h, 1.f,
|
||||
h * kThumbWide, &ow, &oh);
|
||||
} else {
|
||||
thumb_dest_params(result.geometry_w, result.geometry_h, job.thumb_size,
|
||||
job.dpr, job.atlas_max, &ow, &oh);
|
||||
thumb_dest_params(result.geometry_w, result.geometry_h,
|
||||
job.thumb_size, job.dpr, job.atlas_max, &ow, &oh);
|
||||
}
|
||||
const double scale = min(double(ow) / double(result.geometry_w),
|
||||
double(oh) / double(result.geometry_h));
|
||||
@@ -669,8 +672,8 @@ make_thumb(shared_ptr<dawn::Cmm> cmm, const ThumbJob &job)
|
||||
result.transfer = profile_transfer(ctx.screen_profile.get());
|
||||
result.gpu_purpose = job.cacheable
|
||||
? (job.priority == Thumbnailer::Priority::Dimensions
|
||||
? GpuPurpose::CacheOnly
|
||||
: GpuPurpose::CacheDisplay)
|
||||
? GpuPurpose::CacheOnly
|
||||
: GpuPurpose::CacheDisplay)
|
||||
: GpuPurpose::Display;
|
||||
result.tier = tier;
|
||||
result.persistent_checked = job.cacheable;
|
||||
@@ -769,7 +772,7 @@ load_thumb(Thumbnailer &thumbnailer, Thumbnailer::Client client,
|
||||
gpu.src_h = src.height;
|
||||
gpu.outputs = job.cacheable
|
||||
? bundle_outputs(
|
||||
update.geometry_w, update.geometry_h, update.tier)
|
||||
update.geometry_w, update.geometry_h, update.tier)
|
||||
: vector<dawn::ThumbScaler::Job::Output>{{ow, oh, -1}};
|
||||
gpu.orientation = update.orientation;
|
||||
gpu.transfer = update.transfer;
|
||||
@@ -927,14 +930,14 @@ repack_atlas(Browser &b, Browser::File &wanted)
|
||||
if (&f == &wanted || thumb_in_band(b, f, pad))
|
||||
active.push_back(&f);
|
||||
}
|
||||
sort(active.begin(), active.end(), [](const Browser::File *a,
|
||||
const Browser::File *other) {
|
||||
if (a->ram_h != other->ram_h)
|
||||
return a->ram_h > other->ram_h;
|
||||
return a->ram_w > other->ram_w;
|
||||
});
|
||||
sort(active.begin(), active.end(),
|
||||
[](const Browser::File *a, const Browser::File *other) {
|
||||
if (a->ram_h != other->ram_h)
|
||||
return a->ram_h > other->ram_h;
|
||||
return a->ram_w > other->ram_w;
|
||||
});
|
||||
for (int side = max(Sheet::kSize, b.sheet_.w); side <= cap;
|
||||
side = side < cap ? min(cap, side * 2) : cap + 1) {
|
||||
side = side < cap ? min(cap, side * 2) : cap + 1) {
|
||||
Sheet fresh(side, false);
|
||||
vector<Sheet::Packed> placements;
|
||||
placements.reserve(active.size());
|
||||
@@ -954,8 +957,8 @@ repack_atlas(Browser &b, Browser::File &wanted)
|
||||
for (size_t i = 0; i < active.size(); ++i) {
|
||||
Browser::File &f = *active[i];
|
||||
const Sheet::Packed &slot = placements[i];
|
||||
uploads.push_back({f.ram.data(), f.ram_w, f.ram_h,
|
||||
slot.x, slot.y});
|
||||
uploads.push_back(
|
||||
{f.ram.data(), f.ram_w, f.ram_h, slot.x, slot.y});
|
||||
}
|
||||
if (uploads.empty() || !renderer->rebuild_thumbs(uploads, side))
|
||||
return false;
|
||||
@@ -1018,8 +1021,8 @@ apply_thumb_gpu(Browser &b, GpuFinish finish, dawn::ThumbScaler::Result res)
|
||||
bundle->image_height = finish.image_h;
|
||||
bundle->top_tier = finish.requested_tier;
|
||||
for (dawn::ThumbScaler::Result::Output &output : res.outputs) {
|
||||
auto pixels = make_shared<const vector<uint16_t>>(
|
||||
std::move(output.data));
|
||||
auto pixels =
|
||||
make_shared<const vector<uint16_t>>(std::move(output.data));
|
||||
bundle->tiers.push_back({output.tag, output.width,
|
||||
output.height, std::move(pixels)});
|
||||
}
|
||||
@@ -1061,8 +1064,8 @@ apply_thumb_gpu(Browser &b, GpuFinish finish, dawn::ThumbScaler::Result res)
|
||||
display.tier = finish.requested_tier;
|
||||
display.screen_icc = std::move(finish.screen_icc);
|
||||
Browser *browser = &b;
|
||||
if (!b.thumbnailer_.submit(b.thumbnail_client_, finish.gen,
|
||||
finish.priority,
|
||||
if (!b.thumbnailer_.submit(
|
||||
b.thumbnail_client_, finish.gen, finish.priority,
|
||||
[browser, display = std::move(display)]() mutable {
|
||||
return display_thumb(browser, std::move(display));
|
||||
},
|
||||
@@ -1199,8 +1202,8 @@ enqueue_thumbs(Browser &b)
|
||||
return;
|
||||
|
||||
const float pad = row_h(b) * kPrefetchRows;
|
||||
const int target_tier = thumbnail_tier_for_height(max(
|
||||
1, int(ceil(double(b.thumb_size_) * double(b.kit_.dpr_)))));
|
||||
const int target_tier = thumbnail_tier_for_height(
|
||||
max(1, int(ceil(double(b.thumb_size_) * double(b.kit_.dpr_)))));
|
||||
vector<int> vis, pre, background;
|
||||
for (int i = 0; i < int(b.files_.size()); ++i) {
|
||||
const Browser::File &f = b.files_[size_t(i)];
|
||||
@@ -1566,8 +1569,7 @@ layout_grid(Browser &b, Rect area)
|
||||
f.cap_text =
|
||||
b.kit_.elide_lines(caption_name(f.name), ow, kCapLines, false);
|
||||
f.cap = {0, 0, ow,
|
||||
b.kit_.text_height(f.cap_text, ow, false) +
|
||||
b.kit_.px(kCapPad)};
|
||||
b.kit_.text_height(f.cap_text, ow, false) + b.kit_.px(kCapPad)};
|
||||
}
|
||||
if (!row.empty() && row_w + gap + ow > avail)
|
||||
flush();
|
||||
@@ -2122,8 +2124,8 @@ set_thumb_size(Browser &b, int size)
|
||||
++b.thumb_gen_;
|
||||
b.thumbnailer_.set_epoch(b.thumbnail_client_, b.thumb_gen_);
|
||||
b.thumb_inflight_.clear();
|
||||
const int target_tier = thumbnail_tier_for_height(max(
|
||||
1, int(ceil(double(b.thumb_size_) * double(b.kit_.dpr_)))));
|
||||
const int target_tier = thumbnail_tier_for_height(
|
||||
max(1, int(ceil(double(b.thumb_size_) * double(b.kit_.dpr_)))));
|
||||
for (Browser::File &f : b.files_) {
|
||||
f.ram_pending = false;
|
||||
f.reservation = 0;
|
||||
@@ -2868,9 +2870,8 @@ Browser::hist_can_forward() const
|
||||
}
|
||||
|
||||
void
|
||||
Browser::set_screen_profile(
|
||||
shared_ptr<dawn::Cmm> cmm, shared_ptr<dawn::Profile> profile,
|
||||
bool force_reload)
|
||||
Browser::set_screen_profile(shared_ptr<dawn::Cmm> cmm,
|
||||
shared_ptr<dawn::Profile> profile, bool force_reload)
|
||||
{
|
||||
auto screen_icc = profile
|
||||
? make_shared<const vector<uint8_t>>(profile->to_bytes())
|
||||
|
||||
+30
-37
@@ -78,8 +78,7 @@ bake_rgb(dawn::Cmm *cmm, dawn::Profile *target, uint8_t r, uint8_t g, uint8_t b)
|
||||
if (!cmm->transform_bgra16(
|
||||
(uint8_t *) pixel, 1, 1, srgb.get(), target, false, false))
|
||||
return colour;
|
||||
return {
|
||||
pixel[2] / 65535.f, pixel[1] / 65535.f, pixel[0] / 65535.f, 1.f};
|
||||
return {pixel[2] / 65535.f, pixel[1] / 65535.f, pixel[0] / 65535.f, 1.f};
|
||||
}
|
||||
|
||||
static Colour
|
||||
@@ -223,8 +222,8 @@ raster_glyph(const QRawFont &raw, quint32 gid, float phase, QPoint *origin)
|
||||
if (ink.isEmpty())
|
||||
return {};
|
||||
// Ink on the border: kPad did not cover the rasteriser's spread.
|
||||
if (ink.left() == 0 || ink.top() == 0 ||
|
||||
ink.right() == img.width() - 1 || ink.bottom() == img.height() - 1)
|
||||
if (ink.left() == 0 || ink.top() == 0 || ink.right() == img.width() - 1 ||
|
||||
ink.bottom() == img.height() - 1)
|
||||
qWarning("glyph %u overflows its %d-pixel pad", gid, kPad);
|
||||
*origin = box.topLeft() + ink.topLeft();
|
||||
return img.copy(ink);
|
||||
@@ -558,8 +557,8 @@ emit_text(Kit &kit, float x, float y, const QString &text, Colour colour,
|
||||
const float cx1 = float(line.cursorToX(mnemonic + 1));
|
||||
// Both font metrics grow downwards from the baseline, which is where
|
||||
// the glyphs of this line sit as well.
|
||||
const int uy = int(lround(
|
||||
double(y) + line.y() + line.ascent() + raw.underlinePosition()));
|
||||
const int uy = int(
|
||||
lround(double(y) + line.y() + line.ascent() + raw.underlinePosition()));
|
||||
const int th = max(1, int(lround(raw.lineThickness())));
|
||||
const int ux0 = int(lround(x + min(cx0, cx1)));
|
||||
const int ux1 = int(lround(x + max(cx0, cx1)));
|
||||
@@ -628,8 +627,7 @@ Widget::paint(Kit &kit) const
|
||||
Widget *
|
||||
Widget::hit_at(float x, float y)
|
||||
{
|
||||
if (!shown() || this->r.empty() ||
|
||||
!this->r.contains(x, y))
|
||||
if (!shown() || this->r.empty() || !this->r.contains(x, y))
|
||||
return nullptr;
|
||||
for (size_t i = child_count(); i > 0; --i) {
|
||||
if (Widget *k = child(i - 1))
|
||||
@@ -793,11 +791,10 @@ Button::paint(Kit &kit) const
|
||||
const float ink_a = (this->enabled_ ? 1.f : 0.375f) *
|
||||
(this->dim ? 0.5f : 1.f) * kit.ink_alpha();
|
||||
if (this->icon)
|
||||
emit_icon(kit, this->r.x + px, this->r.y + (this->r.h - icon) / 2,
|
||||
icon, this->icon, col(kit.colours_[ColourInk], ink_a));
|
||||
emit_icon(kit, this->r.x + px, this->r.y + (this->r.h - icon) / 2, icon,
|
||||
this->icon, col(kit.colours_[ColourInk], ink_a));
|
||||
if (!this->text.isEmpty()) {
|
||||
const int tx =
|
||||
this->r.x + px + (this->icon ? icon + kit.px(4.f) : 0);
|
||||
const int tx = this->r.x + px + (this->icon ? icon + kit.px(4.f) : 0);
|
||||
const int th = kit.text_height(this->text, 0, false);
|
||||
const QString shown = button_shown(kit, *this);
|
||||
emit_text(kit, float(tx), float(this->r.y + (this->r.h - th) / 2),
|
||||
@@ -927,14 +924,14 @@ Checkbox::paint(Kit &kit) const
|
||||
kit.list_.add_rect_filled_vgradient({bx, by, bx + box, by + box},
|
||||
col(kit.colours_[ColourEntryTop]),
|
||||
col(kit.colours_[ColourEntryBottom]));
|
||||
kit.draw_border({bx, by, box, box}, col(kit.colours_[ColourDivider]),
|
||||
kit.hairline());
|
||||
kit.draw_border(
|
||||
{bx, by, box, box}, col(kit.colours_[ColourDivider]), kit.hairline());
|
||||
|
||||
const float ink_a = (this->enabled_ ? 1.f : 0.375f) *
|
||||
(this->dim ? 0.5f : 1.f) * kit.ink_alpha();
|
||||
if (this->checked)
|
||||
emit_icon(kit, bx + border, by + border, icon,
|
||||
"object-select-symbolic", col(kit.colours_[ColourInk], ink_a));
|
||||
emit_icon(kit, bx + border, by + border, icon, "object-select-symbolic",
|
||||
col(kit.colours_[ColourInk], ink_a));
|
||||
if (!this->text.isEmpty()) {
|
||||
const int tx = bx + box + kit.px(4.f);
|
||||
const int th = kit.text_height(this->text, 0, false);
|
||||
@@ -981,8 +978,7 @@ Label::measure(Kit &kit, int max_w, int)
|
||||
w = max(1, iw < kUnlim ? iw : w);
|
||||
this->r.w = w + pad_x * 2;
|
||||
this->r.h =
|
||||
kit.text_height(this->text, this->wrap ? w : 0, this->bold) +
|
||||
pad_y * 2;
|
||||
kit.text_height(this->text, this->wrap ? w : 0, this->bold) + pad_y * 2;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1294,8 +1290,7 @@ Entry::press(Kit &kit, float x, float, Qt::MouseButton button)
|
||||
// A click during composition would land in the middle of text the input
|
||||
// method still owns; let it finish rather than fighting over the caret.
|
||||
if (this->preedit.isEmpty()) {
|
||||
const Rect in =
|
||||
this->r.inset(kit.px(this->pad_x), kit.px(kEntryPadY));
|
||||
const Rect in = this->r.inset(kit.px(this->pad_x), kit.px(kEntryPadY));
|
||||
move_caret(kit,
|
||||
kit.index_at(this->text, x - float(in.x) + this->scroll_, false));
|
||||
}
|
||||
@@ -2050,8 +2045,7 @@ ScrollColumn::arrange(Kit &kit, Rect alloc)
|
||||
this->scroll_.offset = y0;
|
||||
else if (y0 + float(f->r.h) >
|
||||
this->scroll_.offset + float(alloc.h))
|
||||
this->scroll_.offset =
|
||||
y0 + float(f->r.h) - float(alloc.h);
|
||||
this->scroll_.offset = y0 + float(f->r.h) - float(alloc.h);
|
||||
this->scroll_.clamp();
|
||||
break;
|
||||
}
|
||||
@@ -2082,8 +2076,7 @@ ScrollColumn::paint(Kit &kit) const
|
||||
Widget *
|
||||
ScrollColumn::hit_at(float x, float y)
|
||||
{
|
||||
if (!shown() || this->r.empty() ||
|
||||
!this->r.contains(x, y))
|
||||
if (!shown() || this->r.empty() || !this->r.contains(x, y))
|
||||
return nullptr;
|
||||
if (this->scroll_.visible() &&
|
||||
this->scroll_.bar_rect(this->r).contains(x, y))
|
||||
@@ -2227,9 +2220,8 @@ Panel::paint(Kit &kit) const
|
||||
kit.draw_border(this->r, col(kit.colours_[ColourDivider]), hair);
|
||||
break;
|
||||
case Stroke::Bottom:
|
||||
kit.list_.add_rect_filled(
|
||||
{this->r.x, this->r.bottom() - hair, this->r.right(),
|
||||
this->r.bottom()},
|
||||
kit.list_.add_rect_filled({this->r.x, this->r.bottom() - hair,
|
||||
this->r.right(), this->r.bottom()},
|
||||
col(this->busy ? kit.colours_[ColourBusy]
|
||||
: kit.colours_[ColourDivider]));
|
||||
break;
|
||||
@@ -2457,8 +2449,7 @@ Dialog::place(Kit &kit)
|
||||
// Centred on the window, not on whatever the toolbar left over. The
|
||||
// margin is only there to keep the shadow off the edges.
|
||||
const int margin = kit.px(kGlowPts * 2.f);
|
||||
const int max_w =
|
||||
max(1, min(kit.px(560.f), kit.host_w_ - margin * 2));
|
||||
const int max_w = max(1, min(kit.px(560.f), kit.host_w_ - margin * 2));
|
||||
const int avail_h = max(1, kit.host_h_ - margin * 2);
|
||||
this->frame->measure(kit, max_w, avail_h);
|
||||
// Taller than that means the body scrolls inside it.
|
||||
@@ -2520,20 +2511,20 @@ Dialog::motion(Kit &, float, float)
|
||||
|
||||
// --- Menus -------------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr float kItemGap = 2.f;
|
||||
constexpr float kMenuPad = 4.f;
|
||||
constexpr float kMenuHoldMs = 500.f; // GTK MENU_SHELL_TIMEOUT
|
||||
|
||||
unique_ptr<Sep>
|
||||
static unique_ptr<Sep>
|
||||
hsep()
|
||||
{
|
||||
return make_unique<Sep>();
|
||||
}
|
||||
|
||||
// Where an item's columns land, relative to its own left edge.
|
||||
namespace
|
||||
{
|
||||
|
||||
struct MenuCols {
|
||||
int label_x = 0;
|
||||
int accel_x = 0;
|
||||
@@ -2651,8 +2642,9 @@ MenuPopup::key(Kit &kit, const Key &ev)
|
||||
{
|
||||
if (Popup::key(kit, ev))
|
||||
return true;
|
||||
if (ev.mods & unsigned(Qt::AltModifier | Qt::ShiftModifier |
|
||||
Qt::ControlModifier | Qt::MetaModifier))
|
||||
if (ev.mods &
|
||||
unsigned(Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier |
|
||||
Qt::MetaModifier))
|
||||
return false;
|
||||
|
||||
switch (ev.key) {
|
||||
@@ -2838,8 +2830,9 @@ Overflow::key(Kit &kit, const Key &ev)
|
||||
{
|
||||
if (Popup::key(kit, ev))
|
||||
return true;
|
||||
if (ev.mods & unsigned(Qt::AltModifier | Qt::ShiftModifier |
|
||||
Qt::ControlModifier | Qt::MetaModifier))
|
||||
if (ev.mods &
|
||||
unsigned(Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier |
|
||||
Qt::MetaModifier))
|
||||
return false;
|
||||
|
||||
// Keys reach a popup by bubbling out of the focused widget, so a field
|
||||
|
||||
+26
-32
@@ -34,8 +34,6 @@ using namespace std;
|
||||
|
||||
namespace dn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr array<int, 4> kHeights = {128, 256, 512, 1024};
|
||||
constexpr array<const char *, 4> kNames = {
|
||||
@@ -48,11 +46,16 @@ constexpr const char *kImageWidth = "Thumb::Image::Width";
|
||||
constexpr const char *kImageHeight = "Thumb::Image::Height";
|
||||
constexpr const char *kColorSpace = "Thumb::ColorSpace";
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Metadata {
|
||||
unordered_map<string, string> values;
|
||||
};
|
||||
|
||||
bool
|
||||
} // namespace
|
||||
|
||||
static bool
|
||||
parse_metadata(const uint8_t *data, size_t size, Metadata *out)
|
||||
{
|
||||
if (!out || !data || !size || data[size - 1] != 0)
|
||||
@@ -80,7 +83,7 @@ parse_metadata(const uint8_t *data, size_t size, Metadata *out)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
number(const string &text, uint64_t *out)
|
||||
{
|
||||
if (!out || text.empty())
|
||||
@@ -95,14 +98,14 @@ number(const string &text, uint64_t *out)
|
||||
return true;
|
||||
}
|
||||
|
||||
const string *
|
||||
static const string *
|
||||
value(const Metadata &meta, const char *key)
|
||||
{
|
||||
auto it = meta.values.find(key);
|
||||
return it == meta.values.end() ? nullptr : &it->second;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
valid_metadata(const Metadata &meta, const ThumbnailSource &source)
|
||||
{
|
||||
const string *uri = value(meta, kUri);
|
||||
@@ -116,7 +119,7 @@ valid_metadata(const Metadata &meta, const ThumbnailSource &source)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
read_image_dimensions(const Metadata &meta, ThumbnailHit *hit)
|
||||
{
|
||||
const string *width = value(meta, kImageWidth);
|
||||
@@ -129,7 +132,7 @@ read_image_dimensions(const Metadata &meta, ThumbnailHit *hit)
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray
|
||||
static QByteArray
|
||||
read_file(const QString &path)
|
||||
{
|
||||
QFile file(path);
|
||||
@@ -138,7 +141,7 @@ read_file(const QString &path)
|
||||
return file.readAll();
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
webp_metadata(const QByteArray &bytes, Metadata *meta)
|
||||
{
|
||||
WebPData data{reinterpret_cast<const uint8_t *>(bytes.constData()),
|
||||
@@ -157,7 +160,7 @@ webp_metadata(const QByteArray &bytes, Metadata *meta)
|
||||
return ok;
|
||||
}
|
||||
|
||||
dawn::ImagePtr
|
||||
static dawn::ImagePtr
|
||||
decode_webp(const QByteArray &bytes, dawn::Cmm &cmm, dawn::Profile *source,
|
||||
dawn::Profile *target)
|
||||
{
|
||||
@@ -178,7 +181,7 @@ decode_webp(const QByteArray &bytes, dawn::Cmm &cmm, dawn::Profile *source,
|
||||
return image;
|
||||
}
|
||||
|
||||
ThumbnailHit
|
||||
static ThumbnailHit
|
||||
read_wide(const QString &path, const ThumbnailSource &source, int tier,
|
||||
int desired_tier, const shared_ptr<dawn::Cmm> &cmm, dawn::Profile *screen)
|
||||
{
|
||||
@@ -209,7 +212,7 @@ read_wide(const QString &path, const ThumbnailSource &source, int tier,
|
||||
return hit;
|
||||
}
|
||||
|
||||
ThumbnailHit
|
||||
static ThumbnailHit
|
||||
read_png(const QString &path, const ThumbnailSource &source, int tier,
|
||||
const shared_ptr<dawn::Cmm> &cmm, dawn::Profile *screen)
|
||||
{
|
||||
@@ -252,7 +255,7 @@ read_png(const QString &path, const ThumbnailSource &source, int tier,
|
||||
return hit;
|
||||
}
|
||||
|
||||
QString
|
||||
static QString
|
||||
cache_path(const ThumbnailSource &source, int tier, bool wide)
|
||||
{
|
||||
if (tier < 0 || tier >= int(kNames.size()))
|
||||
@@ -263,7 +266,7 @@ cache_path(const ThumbnailSource &source, int tier, bool wide)
|
||||
.filePath(QString::fromLatin1(source.hash) + (wide ? ".webp" : ".png"));
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
append_field(QByteArray &out, const char *key, const QByteArray &value)
|
||||
{
|
||||
out.append(key);
|
||||
@@ -272,7 +275,7 @@ append_field(QByteArray &out, const char *key, const QByteArray &value)
|
||||
out.append('\0');
|
||||
}
|
||||
|
||||
QByteArray
|
||||
static QByteArray
|
||||
make_metadata(
|
||||
const ThumbnailSource &source, uint32_t image_width, uint32_t image_height)
|
||||
{
|
||||
@@ -286,7 +289,7 @@ make_metadata(
|
||||
return out;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
remove_thumbnail(const QString &path, const QString &reason)
|
||||
{
|
||||
qInfo("%s: deleting: %s", qUtf8Printable(path), qUtf8Printable(reason));
|
||||
@@ -296,8 +299,6 @@ remove_thumbnail(const QString &path, const QString &reason)
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
QString
|
||||
thumbnail_cache_root()
|
||||
{
|
||||
@@ -507,16 +508,14 @@ thumbnail_cache_invalidate_one(const QString &path)
|
||||
{
|
||||
Metadata meta;
|
||||
if (!webp_metadata(read_file(path), &meta)) {
|
||||
remove_thumbnail(
|
||||
path, QStringLiteral("invalid thumbnail metadata"));
|
||||
remove_thumbnail(path, QStringLiteral("invalid thumbnail metadata"));
|
||||
return;
|
||||
}
|
||||
const string *uri_text = value(meta, kUri);
|
||||
const string *mtime_text = value(meta, kMtime);
|
||||
uint64_t mtime = 0, size = 0;
|
||||
if (!uri_text || !mtime_text || !number(*mtime_text, &mtime)) {
|
||||
remove_thumbnail(
|
||||
path, QStringLiteral("missing thumbnail identity"));
|
||||
remove_thumbnail(path, QStringLiteral("missing thumbnail identity"));
|
||||
return;
|
||||
}
|
||||
const QByteArray uri(uri_text->data(), qsizetype(uri_text->size()));
|
||||
@@ -529,14 +528,12 @@ thumbnail_cache_invalidate_one(const QString &path)
|
||||
}
|
||||
const QUrl url = QUrl::fromEncoded(uri);
|
||||
if (!url.isLocalFile()) {
|
||||
qWarning(
|
||||
"%s: cannot verify non-local URI", qUtf8Printable(path));
|
||||
qWarning("%s: cannot verify non-local URI", qUtf8Printable(path));
|
||||
return;
|
||||
}
|
||||
const QFileInfo target(url.toLocalFile());
|
||||
if (!target.exists()) {
|
||||
remove_thumbnail(
|
||||
path, QStringLiteral("source no longer exists"));
|
||||
remove_thumbnail(path, QStringLiteral("source no longer exists"));
|
||||
return;
|
||||
}
|
||||
if (!target.isReadable()) {
|
||||
@@ -544,15 +541,12 @@ thumbnail_cache_invalidate_one(const QString &path)
|
||||
return;
|
||||
}
|
||||
if (target.lastModified().toSecsSinceEpoch() != qint64(mtime)) {
|
||||
remove_thumbnail(
|
||||
path, QStringLiteral("modification time mismatch"));
|
||||
remove_thumbnail(path, QStringLiteral("modification time mismatch"));
|
||||
return;
|
||||
}
|
||||
if (const string *size_text = value(meta, kSize)) {
|
||||
if (!number(*size_text, &size) ||
|
||||
uint64_t(target.size()) != size)
|
||||
remove_thumbnail(
|
||||
path, QStringLiteral("file size mismatch"));
|
||||
if (!number(*size_text, &size) || uint64_t(target.size()) != size)
|
||||
remove_thumbnail(path, QStringLiteral("file size mismatch"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-13
@@ -24,10 +24,8 @@ using namespace std;
|
||||
|
||||
namespace dn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
QString
|
||||
static QString
|
||||
xdg_home_dir(const char *var, const char *default_rel)
|
||||
{
|
||||
const QString env = qEnvironmentVariable(var);
|
||||
@@ -39,7 +37,7 @@ xdg_home_dir(const char *var, const char *default_rel)
|
||||
return QDir::cleanPath(QDir(home).filePath(QString::fromUtf8(default_rel)));
|
||||
}
|
||||
|
||||
vector<QString>
|
||||
static vector<QString>
|
||||
split_search_path(const QString &value)
|
||||
{
|
||||
vector<QString> out;
|
||||
@@ -57,7 +55,7 @@ split_search_path(const QString &value)
|
||||
return out;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
append_unique(vector<QString> &dirs, const QString &dir)
|
||||
{
|
||||
if (dir.isEmpty() || !QDir::isAbsolutePath(dir))
|
||||
@@ -70,7 +68,7 @@ append_unique(vector<QString> &dirs, const QString &dir)
|
||||
dirs.push_back(clean);
|
||||
}
|
||||
|
||||
QString
|
||||
static QString
|
||||
read_text_file(const QString &path)
|
||||
{
|
||||
QFile file(path);
|
||||
@@ -82,6 +80,9 @@ read_text_file(const QString &path)
|
||||
return text;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct MimeGlob {
|
||||
QString type;
|
||||
QString glob;
|
||||
@@ -95,7 +96,9 @@ struct MimeDb {
|
||||
vector<MimeGlob> globs;
|
||||
};
|
||||
|
||||
void
|
||||
} // namespace
|
||||
|
||||
static void
|
||||
read_mime_subclasses(const QString &path, MimeDb &db)
|
||||
{
|
||||
const QString text = read_text_file(path);
|
||||
@@ -116,7 +119,7 @@ read_mime_subclasses(const QString &path, MimeDb &db)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
read_mime_globs(const QString &path, bool is_globs2, MimeDb &db)
|
||||
{
|
||||
QFile file(path);
|
||||
@@ -146,7 +149,8 @@ read_mime_globs(const QString &path, bool is_globs2, MimeDb &db)
|
||||
MimeGlob g;
|
||||
g.type = type;
|
||||
g.glob = glob.toLower();
|
||||
g.glob_re = QRegularExpression::fromWildcard(g.glob, Qt::CaseInsensitive);
|
||||
g.glob_re =
|
||||
QRegularExpression::fromWildcard(g.glob, Qt::CaseInsensitive);
|
||||
if (is_globs2)
|
||||
g.weight = f[0].toInt();
|
||||
db.globs.push_back(std::move(g));
|
||||
@@ -154,7 +158,7 @@ read_mime_globs(const QString &path, bool is_globs2, MimeDb &db)
|
||||
return true;
|
||||
}
|
||||
|
||||
const MimeDb &
|
||||
static const MimeDb &
|
||||
mime_db()
|
||||
{
|
||||
static const MimeDb db = [] {
|
||||
@@ -176,7 +180,7 @@ mime_db()
|
||||
return db;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
add_applying_transitive_closure(const QString &element,
|
||||
const unordered_map<QString, unordered_set<QString>> &relation,
|
||||
unordered_set<QString> &output)
|
||||
@@ -193,8 +197,6 @@ add_applying_transitive_closure(const QString &element,
|
||||
add_applying_transitive_closure(sub, relation, output);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
vector<QString>
|
||||
xdg_data_dirs()
|
||||
{
|
||||
|
||||
+13
-13
@@ -26,20 +26,17 @@
|
||||
using namespace std;
|
||||
namespace fs = filesystem;
|
||||
|
||||
namespace
|
||||
{
|
||||
static mutex io_mu;
|
||||
static atomic<bool> any_fail{false};
|
||||
|
||||
mutex io_mu;
|
||||
atomic<bool> any_fail{false};
|
||||
|
||||
void
|
||||
static void
|
||||
log_err(const string &msg)
|
||||
{
|
||||
lock_guard lock(io_mu);
|
||||
fprintf(stderr, "%s\n", msg.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
fit_size(uint32_t w, uint32_t h, uint32_t *out_w, uint32_t *out_h)
|
||||
{
|
||||
const float scale = min(1.0f, min(512.0f / float(w), 256.0f / float(h)));
|
||||
@@ -47,7 +44,7 @@ fit_size(uint32_t w, uint32_t h, uint32_t *out_w, uint32_t *out_h)
|
||||
*out_h = max(1u, uint32_t(float(h) * scale + 0.5f));
|
||||
}
|
||||
|
||||
fs::path
|
||||
static fs::path
|
||||
thumb_path(const fs::path &input)
|
||||
{
|
||||
const fs::path dir = input.parent_path();
|
||||
@@ -55,7 +52,7 @@ thumb_path(const fs::path &input)
|
||||
return dir / (stem + ".thumb.webp");
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
process_one(const string &path, dawn::ScaleScaler *scaler)
|
||||
{
|
||||
dawn::OpenContext ctx;
|
||||
@@ -120,6 +117,9 @@ process_one(const string &path, dawn::ScaleScaler *scaler)
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct JobQueue {
|
||||
mutex mu;
|
||||
condition_variable cv;
|
||||
@@ -141,7 +141,9 @@ struct JobQueue {
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
} // namespace
|
||||
|
||||
static void
|
||||
worker(JobQueue *jobs, dawn::ScaleScaler *scaler)
|
||||
{
|
||||
for (;;) {
|
||||
@@ -160,14 +162,12 @@ worker(JobQueue *jobs, dawn::ScaleScaler *scaler)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
usage(const char *argv0)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s [-j N] IMAGE...\n", argv0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
||||
+6
-10
@@ -20,17 +20,15 @@ using namespace std;
|
||||
|
||||
namespace dawn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
void
|
||||
static void
|
||||
fail(Error *error, const char *message)
|
||||
{
|
||||
if (error)
|
||||
*error = {Error::Code::Io, message};
|
||||
}
|
||||
|
||||
CFStringRef
|
||||
static CFStringRef
|
||||
make_cfstring(string_view value, Error *error)
|
||||
{
|
||||
CFStringRef result = CFStringCreateWithBytes(kCFAllocatorDefault,
|
||||
@@ -41,7 +39,7 @@ make_cfstring(string_view value, Error *error)
|
||||
return result;
|
||||
}
|
||||
|
||||
optional<string>
|
||||
static optional<string>
|
||||
to_utf8(CFStringRef value, Error *error)
|
||||
{
|
||||
const CFIndex length = CFStringGetLength(value);
|
||||
@@ -56,8 +54,6 @@ to_utf8(CFStringRef value, Error *error)
|
||||
return string(bytes.data());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
optional<string>
|
||||
config_get(string_view key, Error *error)
|
||||
{
|
||||
@@ -66,9 +62,9 @@ config_get(string_view key, Error *error)
|
||||
CFStringRef cf_key = make_cfstring(key, error);
|
||||
if (!cf_key)
|
||||
return nullopt;
|
||||
CFPropertyListRef value = CFPreferencesCopyValue(cf_key,
|
||||
CFSTR(DAWN_NAMESPACE), kCFPreferencesCurrentUser,
|
||||
kCFPreferencesAnyHost);
|
||||
CFPropertyListRef value =
|
||||
CFPreferencesCopyValue(cf_key, CFSTR(DAWN_NAMESPACE),
|
||||
kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
|
||||
CFRelease(cf_key);
|
||||
if (!value)
|
||||
return nullopt;
|
||||
|
||||
+11
-10
@@ -21,10 +21,8 @@ using namespace std;
|
||||
|
||||
namespace dawn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
void
|
||||
static void
|
||||
fail(Error *error, const char *operation, LSTATUS status = ERROR_SUCCESS)
|
||||
{
|
||||
if (!error)
|
||||
@@ -35,7 +33,7 @@ fail(Error *error, const char *operation, LSTATUS status = ERROR_SUCCESS)
|
||||
error->message += ": Windows error " + to_string(status);
|
||||
}
|
||||
|
||||
optional<wstring>
|
||||
static optional<wstring>
|
||||
to_wide(string_view value, Error *error)
|
||||
{
|
||||
if (value.empty())
|
||||
@@ -48,14 +46,14 @@ to_wide(string_view value, Error *error)
|
||||
}
|
||||
wstring out(size_t(size), L'\0');
|
||||
if (!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, value.data(),
|
||||
int(value.size()), out.data(), size)) {
|
||||
int(value.size()), out.data(), size)) {
|
||||
fail(error, "cannot convert configuration string", GetLastError());
|
||||
return nullopt;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
optional<string>
|
||||
static optional<string>
|
||||
to_utf8(wstring_view value, Error *error)
|
||||
{
|
||||
if (value.empty())
|
||||
@@ -68,19 +66,24 @@ to_utf8(wstring_view value, Error *error)
|
||||
}
|
||||
string out(size_t(size), '\0');
|
||||
if (!WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, value.data(),
|
||||
int(value.size()), out.data(), size, nullptr, nullptr)) {
|
||||
int(value.size()), out.data(), size, nullptr, nullptr)) {
|
||||
fail(error, "cannot convert configuration string", GetLastError());
|
||||
return nullopt;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct RegistryName {
|
||||
wstring subkey;
|
||||
wstring value;
|
||||
};
|
||||
|
||||
optional<RegistryName>
|
||||
} // namespace
|
||||
|
||||
static optional<RegistryName>
|
||||
registry_name(string_view key, Error *error)
|
||||
{
|
||||
const size_t slash = key.rfind('/');
|
||||
@@ -100,8 +103,6 @@ registry_name(string_view key, Error *error)
|
||||
return RegistryName{std::move(*wide_subkey), std::move(*wide_value)};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
optional<string>
|
||||
config_get(string_view key, Error *error)
|
||||
{
|
||||
|
||||
+12
-11
@@ -24,19 +24,22 @@ namespace dawn
|
||||
{
|
||||
namespace ipc
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
// Overlapped writes pin their buffer until completion; keep that bounded
|
||||
// rather than hand the kernel a whole output queue.
|
||||
constexpr size_t kWriteChunk = 256 * 1024;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct LocalFreeDeleter {
|
||||
void operator()(void *p) const { ::LocalFree((HLOCAL) p); }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// The token user of a process, as an owned SID copy.
|
||||
vector<std::byte>
|
||||
static vector<std::byte>
|
||||
process_sid(DWORD pid)
|
||||
{
|
||||
vector<std::byte> out;
|
||||
@@ -67,14 +70,14 @@ process_sid(DWORD pid)
|
||||
return out;
|
||||
}
|
||||
|
||||
const vector<std::byte> &
|
||||
static const vector<std::byte> &
|
||||
own_sid()
|
||||
{
|
||||
static const vector<std::byte> sid = process_sid(::GetCurrentProcessId());
|
||||
return sid;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
sid_is_own(const vector<std::byte> &sid)
|
||||
{
|
||||
return !sid.empty() && !own_sid().empty() &&
|
||||
@@ -83,7 +86,7 @@ sid_is_own(const vector<std::byte> &sid)
|
||||
|
||||
// Pipe names are machine-global, so both the user and the Windows session
|
||||
// have to be in there: one user may be logged into several sessions.
|
||||
wstring
|
||||
static wstring
|
||||
pipe_name(string_view service)
|
||||
{
|
||||
if (own_sid().empty())
|
||||
@@ -108,7 +111,7 @@ pipe_name(string_view service)
|
||||
}
|
||||
|
||||
// Deny everyone but the pipe's creator.
|
||||
bool
|
||||
static bool
|
||||
own_user_only(SECURITY_ATTRIBUTES &sa, unique_ptr<void, LocalFreeDeleter> &sd)
|
||||
{
|
||||
wchar_t *text = nullptr;
|
||||
@@ -131,7 +134,7 @@ own_user_only(SECURITY_ATTRIBUTES &sa, unique_ptr<void, LocalFreeDeleter> &sd)
|
||||
return true;
|
||||
}
|
||||
|
||||
HANDLE
|
||||
static HANDLE
|
||||
create_instance(const wstring &name, bool first)
|
||||
{
|
||||
SECURITY_ATTRIBUTES sa{};
|
||||
@@ -154,7 +157,7 @@ create_instance(const wstring &name, bool first)
|
||||
|
||||
// There is no SO_PEERCRED here. Impersonation gives the server the client's
|
||||
// real token; a client can only go by the server's process identity.
|
||||
bool
|
||||
static bool
|
||||
client_is_own_user(HANDLE pipe)
|
||||
{
|
||||
if (!::ImpersonateNamedPipeClient(pipe)) {
|
||||
@@ -180,8 +183,6 @@ client_is_own_user(HANDLE pipe)
|
||||
return same;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// --- Connection --------------------------------------------------------------
|
||||
|
||||
struct Connection::Impl {
|
||||
|
||||
+2
-7
@@ -1555,9 +1555,6 @@ exif_orientation(span<const uint8_t> exif)
|
||||
|
||||
// --- Loaders -----------------------------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// The order is the default loading order.
|
||||
constexpr Loader kLoaders[] = {
|
||||
{"libjpeg-turbo", &detail::load_jpeg, "JPEG", {"image/jpeg"}, {}},
|
||||
@@ -1582,8 +1579,8 @@ constexpr Loader kLoaders[] = {
|
||||
{"ICNS", &detail::load_icns, "ICNS", {"image/x-icns"}, {}},
|
||||
|
||||
// Try to extract full-size previews from TIFF/EP-compatible raws.
|
||||
{"TIFF/EP previews", &detail::load_tiff_ep, "raw photos",
|
||||
{"image/x-dcraw"}, {}},
|
||||
{"TIFF/EP previews", &detail::load_tiff_ep, "raw photos", {"image/x-dcraw"},
|
||||
{}},
|
||||
|
||||
{"LibRaw",
|
||||
#if DAWN_WITH_LIBRAW
|
||||
@@ -1695,8 +1692,6 @@ constexpr Loader kLoaders[] = {
|
||||
{}, {}, {}},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// A subset of shared-mime-info, chiefly motivated by the suckiness of raw
|
||||
// photo formats: someone else will maintain the list of file extensions for us.
|
||||
std::vector<std::string>
|
||||
|
||||
+6
-6
@@ -28,15 +28,12 @@ using namespace std;
|
||||
namespace dawn
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// All pages of a document share it, and outlive load_cgpdf().
|
||||
using DocumentPtr = shared_ptr<CGPDFDocument>;
|
||||
|
||||
// The crop box is what a page means to show, and the drawing transform
|
||||
// takes care of both its origin and the page's /Rotate.
|
||||
void
|
||||
static void
|
||||
cgpdf_page_size(CGPDFPageRef page, double *width, double *height)
|
||||
{
|
||||
CGRect box = CGPDFPageGetBoxRect(page, kCGPDFCropBox);
|
||||
@@ -48,6 +45,9 @@ cgpdf_page_size(CGPDFPageRef page, double *width, double *height)
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class CGPDFRenderClosure : public RenderClosure
|
||||
{
|
||||
DocumentPtr document_;
|
||||
@@ -65,6 +65,8 @@ public:
|
||||
double scale, const OpenContext &ctx, Error *error);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ImagePtr
|
||||
CGPDFRenderClosure::render(Cmm *cmm, Profile *target, double scale)
|
||||
{
|
||||
@@ -157,8 +159,6 @@ CGPDFRenderClosure::render_internal(
|
||||
return image;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ImagePtr
|
||||
detail::load_cgpdf(
|
||||
span<const uint8_t> data, const OpenContext &ctx, Error *error)
|
||||
|
||||
+15
-14
@@ -21,8 +21,6 @@ using namespace std;
|
||||
|
||||
namespace dawn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
// --- Decoding context --------------------------------------------------------
|
||||
|
||||
@@ -35,6 +33,9 @@ constexpr size_t kBoxChunk = 4096;
|
||||
// truncated back to 16 bits on the way in.
|
||||
constexpr JxlPixelFormat kFormat = {4, JXL_TYPE_UINT16, JXL_LITTLE_ENDIAN, 0};
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct JxlLoadContext {
|
||||
JxlDecoder *dec = nullptr; ///< libjxl decoder
|
||||
JxlBasicInfo info = {}; ///< Codestream header
|
||||
@@ -55,13 +56,15 @@ struct JxlLoadContext {
|
||||
~JxlLoadContext();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
JxlLoadContext::~JxlLoadContext()
|
||||
{
|
||||
if (dec)
|
||||
JxlDecoderDestroy(dec);
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
setup_decoder(JxlLoadContext &ctx, span<const uint8_t> data, Error *error)
|
||||
{
|
||||
if (JxlDecoderSubscribeEvents(ctx.dec,
|
||||
@@ -94,7 +97,7 @@ setup_decoder(JxlLoadContext &ctx, span<const uint8_t> data, Error *error)
|
||||
// --- Metadata boxes ----------------------------------------------------------
|
||||
|
||||
// Closes off the box in progress, trimming it to what libjxl really wrote.
|
||||
void
|
||||
static void
|
||||
finish_box(JxlLoadContext &ctx)
|
||||
{
|
||||
if (!ctx.box_dest)
|
||||
@@ -108,7 +111,7 @@ finish_box(JxlLoadContext &ctx)
|
||||
|
||||
// Starts collecting a box, if it is one of the two we care about. The rest
|
||||
// are left alone for libjxl to skip over.
|
||||
void
|
||||
static void
|
||||
start_box(JxlLoadContext &ctx)
|
||||
{
|
||||
finish_box(ctx);
|
||||
@@ -128,7 +131,7 @@ start_box(JxlLoadContext &ctx)
|
||||
}
|
||||
|
||||
// Doubles the payload buffer of a box that outgrew it.
|
||||
void
|
||||
static void
|
||||
expand_box(JxlLoadContext &ctx)
|
||||
{
|
||||
size_t used = ctx.box.size() - JxlDecoderReleaseBoxBuffer(ctx.dec);
|
||||
@@ -141,7 +144,7 @@ expand_box(JxlLoadContext &ctx)
|
||||
// payload starts with a four-byte big-endian offset to the TIFF header
|
||||
// (ISO/IEC 18181-2). Left in place, the Exif parser would read that offset
|
||||
// as the byte order mark and reject the whole block.
|
||||
vector<uint8_t>
|
||||
static vector<uint8_t>
|
||||
exif_payload(const vector<uint8_t> &box)
|
||||
{
|
||||
if (box.size() < 4)
|
||||
@@ -158,7 +161,7 @@ exif_payload(const vector<uint8_t> &box)
|
||||
|
||||
// The profile the returned pixels are actually in. We do no conversion here;
|
||||
// dawn colour-manages from this, as it does for every other loader.
|
||||
void
|
||||
static void
|
||||
take_icc_profile(JxlLoadContext &ctx)
|
||||
{
|
||||
size_t size = 0;
|
||||
@@ -177,7 +180,7 @@ take_icc_profile(JxlLoadContext &ctx)
|
||||
|
||||
// Frame durations count ticks, whose length the codestream header defines as
|
||||
// a fraction of a second.
|
||||
bool
|
||||
static bool
|
||||
take_frame_header(JxlLoadContext &ctx, Error *error)
|
||||
{
|
||||
JxlFrameHeader frame = {};
|
||||
@@ -195,7 +198,7 @@ take_frame_header(JxlLoadContext &ctx, Error *error)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
bind_frame_buffer(JxlLoadContext &ctx, Error *error)
|
||||
{
|
||||
size_t size = 0;
|
||||
@@ -214,7 +217,7 @@ bind_frame_buffer(JxlLoadContext &ctx, Error *error)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
append_decoded_frame(JxlLoadContext &ctx, Error *error)
|
||||
{
|
||||
// This also catches a frame arriving before the header we subscribed to.
|
||||
@@ -247,7 +250,7 @@ append_decoded_frame(JxlLoadContext &ctx, Error *error)
|
||||
|
||||
// Pumps the decoder once, dispatching whatever it has to report. Returns
|
||||
// false on failure, and sets `done` once there is nothing left to decode.
|
||||
bool
|
||||
static bool
|
||||
process_event(JxlLoadContext &ctx, bool *done, Error *error)
|
||||
{
|
||||
switch (JxlDecoderProcessInput(ctx.dec)) {
|
||||
@@ -293,8 +296,6 @@ process_event(JxlLoadContext &ctx, bool *done, Error *error)
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// --- Public entry point ------------------------------------------------------
|
||||
|
||||
ImagePtr
|
||||
|
||||
@@ -23,16 +23,13 @@ using namespace std;
|
||||
namespace dawn
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// librsvg/Cairo rendering is capped at the project pixmap limit.
|
||||
constexpr double kMaxDimension = double(dawn::kMaxDimension);
|
||||
constexpr double kMaxRenderDimension = double(dawn::kMaxDimension);
|
||||
|
||||
// Cairo's ARGB32 is a native-endian 0xAARRGGBB word, always premultiplied--
|
||||
// exactly the layout pack_argb32_words_to_bgra16() expects, association
|
||||
// (premultiplication) unchanged.
|
||||
void
|
||||
static void
|
||||
cairo_argb32_to_image(Image &dst, cairo_surface_t *surface)
|
||||
{
|
||||
const uint8_t *base = cairo_image_surface_get_data(surface);
|
||||
@@ -40,6 +37,9 @@ cairo_argb32_to_image(Image &dst, cairo_surface_t *surface)
|
||||
pack_argb32_words_to_bgra16(dst, (const uint32_t *) base, size_t(stride));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class LibrsvgRenderClosure : public RenderClosure
|
||||
{
|
||||
RsvgHandle *handle_;
|
||||
@@ -62,6 +62,8 @@ public:
|
||||
double scale, Cmm *cmm, Profile *target, Error *error);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ImagePtr
|
||||
LibrsvgRenderClosure::render(Cmm *cmm, Profile *target, double scale)
|
||||
{
|
||||
@@ -76,7 +78,7 @@ LibrsvgRenderClosure::render_internal(
|
||||
RsvgRectangle viewport = {
|
||||
.x = 0, .y = 0, .width = width_ * scale, .height = height_ * scale};
|
||||
double w = ceil(viewport.width), h = ceil(viewport.height);
|
||||
if (w < 1 || h < 1 || w > kMaxDimension || h > kMaxDimension) {
|
||||
if (w < 1 || h < 1 || w > kMaxRenderDimension || h > kMaxRenderDimension) {
|
||||
set_error(error, "image dimensions overflow");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -131,8 +133,6 @@ LibrsvgRenderClosure::render_internal(
|
||||
return image;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ImagePtr
|
||||
detail::load_librsvg(
|
||||
span<const uint8_t> data, const OpenContext &ctx, Error *error)
|
||||
|
||||
@@ -22,15 +22,12 @@ using namespace std;
|
||||
namespace dawn
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
namespace fs = filesystem;
|
||||
|
||||
// resvg documents share the project pixmap dimension limit.
|
||||
constexpr double kMaxDimension = double(dawn::kMaxDimension);
|
||||
constexpr double kMaxRenderDimension = double(dawn::kMaxDimension);
|
||||
|
||||
const char *
|
||||
static const char *
|
||||
resvg_error_string(int32_t err)
|
||||
{
|
||||
switch (err) {
|
||||
@@ -51,6 +48,9 @@ resvg_error_string(int32_t err)
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
class ResvgRenderClosure : public RenderClosure
|
||||
{
|
||||
resvg_render_tree *tree_;
|
||||
@@ -73,6 +73,8 @@ public:
|
||||
double scale, Cmm *cmm, Profile *target, Error *error);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ImagePtr
|
||||
ResvgRenderClosure::render(Cmm *cmm, Profile *target, double scale)
|
||||
{
|
||||
@@ -85,7 +87,7 @@ ResvgRenderClosure::render_internal(
|
||||
double scale, Cmm *cmm, Profile *target, Error *error)
|
||||
{
|
||||
double w = ceil(width_ * scale), h = ceil(height_ * scale);
|
||||
if (w < 1 || h < 1 || w > kMaxDimension || h > kMaxDimension) {
|
||||
if (w < 1 || h < 1 || w > kMaxRenderDimension || h > kMaxRenderDimension) {
|
||||
set_error(error, "image dimensions overflow");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -118,8 +120,6 @@ ResvgRenderClosure::render_internal(
|
||||
return image;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ImagePtr
|
||||
detail::load_resvg(
|
||||
span<const uint8_t> data, const OpenContext &ctx, Error *error)
|
||||
|
||||
+14
-13
@@ -23,14 +23,12 @@ using namespace std;
|
||||
|
||||
namespace dawn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
// --- Minimal JPEG dimension sniffing -----------------------------------------
|
||||
// We only need pixel counts to pick the largest preview among candidates--
|
||||
// actual decoding, along with Exif/ICC extraction, is left to load_jpeg().
|
||||
|
||||
int64_t
|
||||
static int64_t
|
||||
jpeg_pixel_count(const uint8_t *data, size_t len)
|
||||
{
|
||||
return detail::jpeg_sof_pixel_count(span<const uint8_t>(data, len));
|
||||
@@ -50,7 +48,7 @@ jpeg_pixel_count(const uint8_t *data, size_t len)
|
||||
// JPEG SubIFDs, and TIFFReadCustomDirectory() takes a privately defined
|
||||
// struct that may not be omitted.)
|
||||
|
||||
bool
|
||||
static bool
|
||||
tiffer_find(const tiffer *self, uint16_t tag, tiffer_entry *entry)
|
||||
{
|
||||
// Note that we could employ binary search, because tags must be ordered:
|
||||
@@ -68,7 +66,7 @@ tiffer_find(const tiffer *self, uint16_t tag, tiffer_entry *entry)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
tiffer_find_integer(const tiffer *self, uint16_t tag, int64_t *i)
|
||||
{
|
||||
tiffer_entry entry = {};
|
||||
@@ -76,7 +74,7 @@ tiffer_find_integer(const tiffer *self, uint16_t tag, int64_t *i)
|
||||
}
|
||||
|
||||
// In case of failure, an entry with a zero "remaining_count" is returned.
|
||||
tiffer_entry
|
||||
static tiffer_entry
|
||||
tiff_ep_subifds_init(const tiffer *T)
|
||||
{
|
||||
tiffer_entry entry = {};
|
||||
@@ -84,7 +82,7 @@ tiff_ep_subifds_init(const tiffer *T)
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
tiff_ep_subifds_next(const tiffer *T, tiffer_entry *subifds, tiffer *subT)
|
||||
{
|
||||
// XXX: Except for a zero "remaining_count", all conditions are errors,
|
||||
@@ -98,7 +96,7 @@ tiff_ep_subifds_next(const tiffer *T, tiffer_entry *subifds, tiffer *subT)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
tiff_ep_find_main(const tiffer *T, tiffer *outputT)
|
||||
{
|
||||
// This is a mandatory field.
|
||||
@@ -121,13 +119,18 @@ tiff_ep_find_main(const tiffer *T, tiffer *outputT)
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct TiffEpJpeg {
|
||||
const uint8_t *jpeg = nullptr; ///< JPEG data stream
|
||||
size_t jpeg_length = 0; ///< JPEG data stream length
|
||||
int64_t pixels = 0; ///< Number of pixels in the JPEG
|
||||
};
|
||||
|
||||
void
|
||||
} // namespace
|
||||
|
||||
static void
|
||||
tiff_ep_find_jpeg_evaluate(const tiffer *T, TiffEpJpeg *out)
|
||||
{
|
||||
// This is a mandatory field.
|
||||
@@ -172,7 +175,7 @@ tiff_ep_find_jpeg_evaluate(const tiffer *T, TiffEpJpeg *out)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
tiff_ep_find_jpeg(const tiffer *T, TiffEpJpeg *out)
|
||||
{
|
||||
// This is a mandatory field.
|
||||
@@ -193,7 +196,7 @@ tiff_ep_find_jpeg(const tiffer *T, TiffEpJpeg *out)
|
||||
return true;
|
||||
}
|
||||
|
||||
ImagePtr
|
||||
static ImagePtr
|
||||
load_tiff_ep_page(const tiffer *T, const OpenContext &ctx, Error *error)
|
||||
{
|
||||
// ISO/DIS 12234-2 is a fuck-up that says this should be in "IFD0",
|
||||
@@ -263,8 +266,6 @@ load_tiff_ep_page(const tiffer *T, const OpenContext &ctx, Error *error)
|
||||
return image;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ImagePtr
|
||||
detail::load_tiff_ep(
|
||||
span<const uint8_t> data, const OpenContext &ctx, Error *error)
|
||||
|
||||
+16
-15
@@ -34,11 +34,12 @@ using namespace std;
|
||||
|
||||
namespace dawn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
// --- In-memory TIFF client adaptor -------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct TiffIo {
|
||||
const OpenContext *ctx = nullptr;
|
||||
const uint8_t *data = nullptr;
|
||||
@@ -46,7 +47,9 @@ struct TiffIo {
|
||||
string error; ///< First hard error encountered, if any
|
||||
};
|
||||
|
||||
tsize_t
|
||||
} // namespace
|
||||
|
||||
static tsize_t
|
||||
tiff_read(thandle_t h, tdata_t buf, tsize_t len)
|
||||
{
|
||||
auto *io = (TiffIo *) h;
|
||||
@@ -66,14 +69,14 @@ tiff_read(thandle_t h, tdata_t buf, tsize_t len)
|
||||
return tsize_t(n);
|
||||
}
|
||||
|
||||
tsize_t
|
||||
static tsize_t
|
||||
tiff_write(thandle_t, tdata_t, tsize_t)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
toff_t
|
||||
static toff_t
|
||||
tiff_seek(thandle_t h, toff_t offset, int whence)
|
||||
{
|
||||
auto *io = (TiffIo *) h;
|
||||
@@ -94,19 +97,19 @@ tiff_seek(thandle_t h, toff_t offset, int whence)
|
||||
return io->position;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
tiff_close(thandle_t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
toff_t
|
||||
static toff_t
|
||||
tiff_size(thandle_t h)
|
||||
{
|
||||
return ((TiffIo *) h)->len;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
tiff_error(thandle_t h, const char *module, const char *format, va_list ap)
|
||||
{
|
||||
auto *io = (TiffIo *) h;
|
||||
@@ -120,7 +123,7 @@ tiff_error(thandle_t h, const char *module, const char *format, va_list ap)
|
||||
add_warning(*io->ctx, string(module) + ": " + buf);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
tiff_warning(thandle_t h, const char *module, const char *format, va_list ap)
|
||||
{
|
||||
auto *io = (TiffIo *) h;
|
||||
@@ -138,7 +141,7 @@ tiff_warning(thandle_t h, const char *module, const char *format, va_list ap)
|
||||
// for ORIENTATION_LEFTTOP normalization already rotates the raster--only
|
||||
// a residual mirroring can remain, and apparently only these two forms of
|
||||
// it (this mirrors what fiv-io.c has empirically established works).
|
||||
void
|
||||
static void
|
||||
apply_tiff_orientation(Image &image, TIFF *tiff)
|
||||
{
|
||||
uint16_t orientation = 0;
|
||||
@@ -150,7 +153,7 @@ apply_tiff_orientation(Image &image, TIFF *tiff)
|
||||
image.orientation = Orientation::Mirror90;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
apply_tiff_metadata(Image &image, TIFF *tiff)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
@@ -167,7 +170,7 @@ apply_tiff_metadata(Image &image, TIFF *tiff)
|
||||
|
||||
// Contiguous unsigned 16-bit grey/RGB(A) that TIFFRGBAImage would only
|
||||
// quantize to 8-bit. Reads scanlines and packs to working BGRA16.
|
||||
ImagePtr
|
||||
static ImagePtr
|
||||
load_tiff_directory_u16(TIFF *tiff, const OpenContext &ctx, Error *error)
|
||||
{
|
||||
uint32_t width = 0, height = 0;
|
||||
@@ -276,7 +279,7 @@ load_tiff_directory_u16(TIFF *tiff, const OpenContext &ctx, Error *error)
|
||||
return image;
|
||||
}
|
||||
|
||||
ImagePtr
|
||||
static ImagePtr
|
||||
load_tiff_directory(TIFF *tiff, const OpenContext &ctx, Error *error)
|
||||
{
|
||||
{
|
||||
@@ -358,8 +361,6 @@ load_tiff_directory(TIFF *tiff, const OpenContext &ctx, Error *error)
|
||||
return image;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ImagePtr
|
||||
detail::load_tiff(
|
||||
span<const uint8_t> data, const OpenContext &ctx, Error *error)
|
||||
|
||||
+17
-17
@@ -46,14 +46,11 @@ using namespace std;
|
||||
namespace dawn
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// --- Metadata pulling --------------------------------------------------------
|
||||
|
||||
constexpr size_t kMaxMetadataSize = 64 * 1024 * 1024;
|
||||
|
||||
bool
|
||||
static bool
|
||||
grow_metadata_buffer(vector<uint8_t> *storage, wuffs_base__io_buffer *dst,
|
||||
size_t required, Error *error)
|
||||
{
|
||||
@@ -69,7 +66,7 @@ grow_metadata_buffer(vector<uint8_t> *storage, wuffs_base__io_buffer *dst,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
pull_passthrough(const wuffs_base__more_information *minfo,
|
||||
wuffs_base__io_buffer *src, vector<uint8_t> *storage,
|
||||
wuffs_base__io_buffer *dst, Error *error)
|
||||
@@ -101,7 +98,7 @@ pull_passthrough(const wuffs_base__more_information *minfo,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
pull_metadata(wuffs_base__image_decoder *dec, wuffs_base__io_buffer *src,
|
||||
wuffs_base__more_information *minfo, vector<uint8_t> *out, Error *error)
|
||||
{
|
||||
@@ -147,6 +144,9 @@ pull_metadata(wuffs_base__image_decoder *dec, wuffs_base__io_buffer *src,
|
||||
|
||||
// --- Frame decoding and composition ------------------------------------------
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct WuffsLoadContext {
|
||||
wuffs_base__image_decoder *dec = nullptr; ///< Wuffs decoder abstraction
|
||||
wuffs_base__io_buffer *src = nullptr; ///< Wuffs source buffer
|
||||
@@ -178,9 +178,11 @@ struct WuffsLoadContext {
|
||||
ImagePtr restore_previous; ///< Canvas before the previous frame
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Crops a rectangular region out of a working-format image, so that it can be
|
||||
// composited at its original position with dn::blend_image().
|
||||
ImagePtr
|
||||
static ImagePtr
|
||||
crop(const Image &src, wuffs_base__rect_ie_u32 r)
|
||||
{
|
||||
uint32_t w = r.max_excl_x - r.min_incl_x;
|
||||
@@ -196,7 +198,7 @@ crop(const Image &src, wuffs_base__rect_ie_u32 r)
|
||||
return out;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
take_reported_metadata(WuffsLoadContext &ctx, Error *error)
|
||||
{
|
||||
wuffs_base__more_information minfo = {};
|
||||
@@ -253,7 +255,7 @@ take_reported_metadata(WuffsLoadContext &ctx, Error *error)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
apply_collected_metadata(WuffsLoadContext &ctx)
|
||||
{
|
||||
for (Image *im = ctx.result.get(); im; im = im->frame_next.get()) {
|
||||
@@ -268,7 +270,7 @@ apply_collected_metadata(WuffsLoadContext &ctx)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
load_wuffs_frame_compose(WuffsLoadContext &ctx, ImagePtr &image,
|
||||
const wuffs_base__frame_config &fc, Error *error)
|
||||
{
|
||||
@@ -340,7 +342,7 @@ load_wuffs_frame_compose(WuffsLoadContext &ctx, ImagePtr &image,
|
||||
|
||||
// https://github.com/google/wuffs/blob/main/example/gifplayer/gifplayer.c
|
||||
// is pure C, and a good reference.
|
||||
bool
|
||||
static bool
|
||||
load_wuffs_frame(WuffsLoadContext &ctx, Error *error)
|
||||
{
|
||||
wuffs_base__frame_config fc = {};
|
||||
@@ -426,7 +428,7 @@ load_wuffs_frame(WuffsLoadContext &ctx, Error *error)
|
||||
return ok;
|
||||
}
|
||||
|
||||
ImagePtr
|
||||
static ImagePtr
|
||||
open_wuffs(wuffs_base__image_decoder *dec, wuffs_base__io_buffer src,
|
||||
const OpenContext &octx, Error *error)
|
||||
{
|
||||
@@ -512,7 +514,7 @@ open_wuffs(wuffs_base__image_decoder *dec, wuffs_base__io_buffer src,
|
||||
return ctx.result;
|
||||
}
|
||||
|
||||
ImagePtr
|
||||
static ImagePtr
|
||||
open_wuffs_using(wuffs_base__image_decoder *(*allocate)(),
|
||||
span<const uint8_t> data, const OpenContext &ctx, Error *error)
|
||||
{
|
||||
@@ -528,8 +530,6 @@ open_wuffs_using(wuffs_base__image_decoder *(*allocate)(),
|
||||
return open_wuffs(dec.get(), src, ctx, error);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// --- Public entry points -----------------------------------------------------
|
||||
|
||||
ImagePtr
|
||||
@@ -572,8 +572,8 @@ detail::load_wuffs(
|
||||
error);
|
||||
case WUFFS_BASE__FOURCC__TGA:
|
||||
return open_wuffs_using(
|
||||
wuffs_targa__decoder__alloc_as__wuffs_base__image_decoder, data, ctx,
|
||||
error);
|
||||
wuffs_targa__decoder__alloc_as__wuffs_base__image_decoder, data,
|
||||
ctx, error);
|
||||
case WUFFS_BASE__FOURCC__WBMP:
|
||||
return open_wuffs_using(
|
||||
wuffs_wbmp__decoder__alloc_as__wuffs_base__image_decoder, data, ctx,
|
||||
|
||||
@@ -22,20 +22,23 @@ using namespace std;
|
||||
|
||||
namespace dawn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
// --- In-memory XcursorFile adaptor -------------------------------------------
|
||||
// libXcursor checks for EOF rather than -1 on short reads, so this needs to
|
||||
// be careful to only ever report exactly as many bytes as were available.
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct MemXcursorFile {
|
||||
XcursorFile parent;
|
||||
const unsigned char *data;
|
||||
long position, len;
|
||||
};
|
||||
|
||||
int
|
||||
} // namespace
|
||||
|
||||
static int
|
||||
xcursor_read(XcursorFile *file, unsigned char *buf, int len)
|
||||
{
|
||||
auto *self = (MemXcursorFile *) file;
|
||||
@@ -55,14 +58,14 @@ xcursor_read(XcursorFile *file, unsigned char *buf, int len)
|
||||
return int(n);
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
xcursor_write(XcursorFile *, unsigned char *, int)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
xcursor_seek(XcursorFile *file, long offset, int whence)
|
||||
{
|
||||
auto *self = (MemXcursorFile *) file;
|
||||
@@ -100,7 +103,7 @@ const XcursorFile kMemXcursorFileAdaptor = {
|
||||
// XcursorImage pixels are native-endian, alpha-premultiplied 0xAARRGGBB
|
||||
// words (libXcursor already byte swaps into host order for us), exactly
|
||||
// the layout pack_argb32_words_to_bgra16() expects.
|
||||
ImagePtr
|
||||
static ImagePtr
|
||||
load_xcursor_image(const XcursorImage *src)
|
||||
{
|
||||
if (!src->width || !src->height)
|
||||
@@ -117,8 +120,6 @@ load_xcursor_image(const XcursorImage *src)
|
||||
return image;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Cursor files bundle multiple pixel sizes of essentially the same picture,
|
||||
// each of which may in turn be animated--map "nominal sizes" to pages,
|
||||
// and animation frames within a nominal size to a per-page frame chain.
|
||||
|
||||
+12
-11
@@ -29,8 +29,6 @@ using namespace std;
|
||||
|
||||
namespace dawn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr uint32_t kMaxTiles = 256;
|
||||
constexpr uint32_t kTileEdge = 4096;
|
||||
@@ -39,6 +37,9 @@ constexpr VkDeviceSize kTileBytesPerPixel = 8;
|
||||
constexpr VkFormat kTileFormat = VK_FORMAT_R16G16B16A16_UNORM;
|
||||
constexpr VkFormat kMidFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct TileRect {
|
||||
int32_t ox = 0, oy = 0, w = 0, h = 0;
|
||||
};
|
||||
@@ -68,18 +69,21 @@ struct PushConstants {
|
||||
float bg_r = 0, bg_g = 0, bg_b = 0;
|
||||
float checker_r = 0, checker_g = 0, checker_b = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static_assert(sizeof(PushConstants) == 92);
|
||||
|
||||
// TODO(p): What in Hell could be a reason for being this lenient?
|
||||
constexpr float kAngleFast = 1e-5f;
|
||||
|
||||
bool
|
||||
static bool
|
||||
view_axis_aligned(const ScaleView &view)
|
||||
{
|
||||
return fabs(view.angle) < kAngleFast;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
use_separable(const ScaleView &view)
|
||||
{
|
||||
if (!view_axis_aligned(view))
|
||||
@@ -89,13 +93,13 @@ use_separable(const ScaleView &view)
|
||||
return view.filter == Filter::Expensive && view.scale < 1.f;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
static uint32_t
|
||||
ceil_div(uint32_t a, uint32_t b)
|
||||
{
|
||||
return b == 0 ? 0 : (a + b - 1) / b;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
check_vk(VkResult r, const char *what, string *error)
|
||||
{
|
||||
if (r != VK_SUCCESS) {
|
||||
@@ -107,8 +111,6 @@ check_vk(VkResult r, const char *what, string *error)
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Filter
|
||||
preferred_filter(VkPhysicalDevice phys)
|
||||
{
|
||||
@@ -1090,9 +1092,8 @@ ScaleEngine::Impl::make_push(const ScaleView &view, uint32_t vp_w,
|
||||
(image_opaque ? (1 << 18) : 0) | (view.linear_blend ? (1 << 19) : 0);
|
||||
// Supply backgrounds in the selected compositing space.
|
||||
auto background = [&](float encoded) {
|
||||
return view.linear_blend
|
||||
? transfer_decode(encoded, view.transfer)
|
||||
: encoded;
|
||||
return view.linear_blend ? transfer_decode(encoded, view.transfer)
|
||||
: encoded;
|
||||
};
|
||||
pc.bg_r = background(clear_rgba[0]);
|
||||
pc.bg_g = background(clear_rgba[1]);
|
||||
|
||||
+17
-16
@@ -32,39 +32,37 @@ using namespace std;
|
||||
|
||||
namespace dawn
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr uint32_t kBatchSlots = 2;
|
||||
constexpr uint32_t kMaxBatchReqs = 64;
|
||||
constexpr uint32_t kMaxDescriptorSets = kMaxBatchReqs * 31;
|
||||
constexpr uint64_t kReducedBudget = 256ull << 20;
|
||||
|
||||
uint64_t
|
||||
static uint64_t
|
||||
align_up(uint64_t v, uint64_t a)
|
||||
{
|
||||
return a ? (v + a - 1) / a * a : v;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
static uint32_t
|
||||
ceil_div(uint32_t a, uint32_t b)
|
||||
{
|
||||
return b ? (a + b - 1) / b : 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
static uint32_t
|
||||
reduced_dim(uint32_t n, uint32_t k)
|
||||
{
|
||||
return k >= 32 ? 1 : ceil_div(n, 1u << k);
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
higher(ThumbScaler::Priority a, ThumbScaler::Priority b)
|
||||
{
|
||||
return static_cast<uint8_t>(a) < static_cast<uint8_t>(b);
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
check_vk(VkResult r, const char *what, string *error)
|
||||
{
|
||||
if (r == VK_SUCCESS)
|
||||
@@ -75,12 +73,17 @@ check_vk(VkResult r, const char *what, string *error)
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct MemoryType {
|
||||
uint32_t index = UINT32_MAX;
|
||||
VkMemoryPropertyFlags flags = 0;
|
||||
};
|
||||
|
||||
MemoryType
|
||||
} // namespace
|
||||
|
||||
static MemoryType
|
||||
pick_memory(VkPhysicalDevice phys, uint32_t bits,
|
||||
VkMemoryPropertyFlags required, VkMemoryPropertyFlags preferred)
|
||||
{
|
||||
@@ -103,7 +106,7 @@ pick_memory(VkPhysicalDevice phys, uint32_t bits,
|
||||
return best;
|
||||
}
|
||||
|
||||
VkShaderModule
|
||||
static VkShaderModule
|
||||
make_shader(
|
||||
VkDevice device, const uint32_t *code, uint32_t words, string *error)
|
||||
{
|
||||
@@ -118,7 +121,7 @@ make_shader(
|
||||
return shader;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
job_size(const ThumbScaler::Job &job, uint64_t *row, uint64_t *bytes)
|
||||
{
|
||||
if (!job.pixels || job.pixels->empty() || !job.src_w || !job.src_h ||
|
||||
@@ -138,8 +141,6 @@ job_size(const ThumbScaler::Job &job, uint64_t *row, uint64_t *bytes)
|
||||
return *bytes <= SIZE_MAX && needed <= available;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct ThumbScaler::Impl {
|
||||
struct Slot {
|
||||
void *mapped = nullptr;
|
||||
@@ -889,12 +890,12 @@ ThumbScaler::Impl::build_batch(
|
||||
orientation_display_size(item.req.src_w, item.req.src_h,
|
||||
item.req.orientation, &item.display_w, &item.display_h);
|
||||
item.mid_off = align_up(mid_bytes, alignment);
|
||||
mid_bytes = item.mid_off + VkDeviceSize(item.req.out_w) *
|
||||
item.display_h * kBytesPerPixel;
|
||||
mid_bytes = item.mid_off +
|
||||
VkDeviceSize(item.req.out_w) * item.display_h * kBytesPerPixel;
|
||||
item.output_off = align_up(output_bytes, alignment);
|
||||
item.readback_off = align_up(readback_bytes, alignment);
|
||||
const VkDeviceSize n = VkDeviceSize(item.req.out_w) *
|
||||
item.req.out_h * kBytesPerPixel;
|
||||
const VkDeviceSize n =
|
||||
VkDeviceSize(item.req.out_w) * item.req.out_h * kBytesPerPixel;
|
||||
output_bytes = item.output_off + n;
|
||||
readback_bytes = item.readback_off + n;
|
||||
b.items.push_back(std::move(item));
|
||||
|
||||
+26
-26
@@ -28,34 +28,36 @@ namespace fs = filesystem;
|
||||
#error DAWN_TEST_FIXTURES_DIR must be defined
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool
|
||||
static bool
|
||||
near_u16(uint16_t a, uint16_t b, uint16_t tol)
|
||||
{
|
||||
return abs(int(a) - int(b)) <= int(tol);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Pixel {
|
||||
uint16_t b = 0, g = 0, r = 0, a = 0;
|
||||
};
|
||||
|
||||
Pixel
|
||||
} // namespace
|
||||
|
||||
static Pixel
|
||||
pixel0(const dawn::Image &img)
|
||||
{
|
||||
const uint16_t *p = dawn::row_u16(img, 0);
|
||||
return {p[0], p[1], p[2], p[3]};
|
||||
}
|
||||
|
||||
Pixel
|
||||
static Pixel
|
||||
pixel_at(const dawn::Image &img, uint32_t x, uint32_t y)
|
||||
{
|
||||
const uint16_t *p = dawn::row_u16(img, y) + x * 4;
|
||||
return {p[0], p[1], p[2], p[3]};
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
expect_bgra(const char *label, Pixel p, uint16_t b, uint16_t g, uint16_t r,
|
||||
uint16_t a, uint16_t tol)
|
||||
{
|
||||
@@ -67,7 +69,7 @@ expect_bgra(const char *label, Pixel p, uint16_t b, uint16_t g, uint16_t r,
|
||||
}
|
||||
}
|
||||
|
||||
dawn::ImagePtr
|
||||
static dawn::ImagePtr
|
||||
load_fixture(const string &name)
|
||||
{
|
||||
fs::path path = fs::path(DAWN_TEST_FIXTURES_DIR) / name;
|
||||
@@ -83,7 +85,7 @@ load_fixture(const string &name)
|
||||
return img;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_pack_helpers()
|
||||
{
|
||||
dawn::ImagePtr img = dawn::image_new(1, 1);
|
||||
@@ -139,7 +141,7 @@ test_pack_helpers()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_solid(const char *path, uint16_t b, uint16_t g, uint16_t r, uint16_t tol)
|
||||
{
|
||||
dawn::ImagePtr img = load_fixture(path);
|
||||
@@ -149,7 +151,7 @@ test_solid(const char *path, uint16_t b, uint16_t g, uint16_t r, uint16_t tol)
|
||||
expect_bgra(path, pixel0(*img), b, g, r, 65535, tol);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_loaders_solid()
|
||||
{
|
||||
struct Solid {
|
||||
@@ -188,7 +190,7 @@ test_loaders_solid()
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_jpeg_cms_8_to_16()
|
||||
{
|
||||
auto cmm = dawn::Cmm::get_default();
|
||||
@@ -217,7 +219,7 @@ test_jpeg_cms_8_to_16()
|
||||
expect_bgra("jpeg cms blue.jpg", pixel0(*img), 65535, 0, 0, 65535, 257 * 2);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_jpeg_fatal_error()
|
||||
{
|
||||
const fs::path path = fs::path(DAWN_TEST_FIXTURES_DIR) / "blue.jpg";
|
||||
@@ -248,7 +250,7 @@ test_jpeg_fatal_error()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_cmyk_cms_opaque()
|
||||
{
|
||||
auto cmm = dawn::Cmm::get_default();
|
||||
@@ -275,7 +277,7 @@ test_cmyk_cms_opaque()
|
||||
CHECK(unsigned(p.b) + p.g + p.r != 0);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_cms_tiled()
|
||||
{
|
||||
auto cmm = dawn::Cmm::get_default();
|
||||
@@ -308,7 +310,7 @@ test_cms_tiled()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_rgbw_2x2()
|
||||
{
|
||||
dawn::ImagePtr img = load_fixture("rgbw_2x2.png");
|
||||
@@ -322,7 +324,7 @@ test_rgbw_2x2()
|
||||
"rgbw[1,1] white", pixel_at(*img, 1, 1), 65535, 65535, 65535, 65535, 0);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_premul_alpha()
|
||||
{
|
||||
dawn::ImagePtr img = load_fixture("red_a128.png");
|
||||
@@ -333,7 +335,7 @@ test_premul_alpha()
|
||||
expect_bgra("red_a128 premul", pixel0(*img), 0, 0, half, half, 1);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_large_icc_and_p3_red()
|
||||
{
|
||||
const fs::path path =
|
||||
@@ -374,7 +376,7 @@ test_large_icc_and_p3_red()
|
||||
CHECK(p3_red.b + 1000 < srgb_red.b);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_svg_solid(const char *path, uint16_t b, uint16_t g, uint16_t r)
|
||||
{
|
||||
dawn::ImagePtr img = load_fixture(path);
|
||||
@@ -400,7 +402,7 @@ test_svg_solid(const char *path, uint16_t b, uint16_t g, uint16_t r)
|
||||
65535, tol);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_svg()
|
||||
{
|
||||
test_svg_solid("red.svg", 0, 0, 65535);
|
||||
@@ -433,7 +435,7 @@ test_svg()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
near_xy(const char *label, double x, double y, double xe, double ye, double tol)
|
||||
{
|
||||
if (fabs(x - xe) > tol || fabs(y - ye) > tol) {
|
||||
@@ -442,7 +444,7 @@ near_xy(const char *label, double x, double y, double xe, double ye, double tol)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_chromaticities()
|
||||
{
|
||||
CHECK(dawn::profile_chromaticities(nullptr).model ==
|
||||
@@ -513,7 +515,7 @@ test_chromaticities()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_png_text_after_idat()
|
||||
{
|
||||
fs::path path = fs::path(DAWN_TEST_FIXTURES_DIR) / "text-after-idat.png";
|
||||
@@ -539,7 +541,7 @@ test_png_text_after_idat()
|
||||
CHECK(it->second == "hello");
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_profile_transfer()
|
||||
{
|
||||
CHECK(dawn::profile_transfer(nullptr) == dawn::Transfer::Srgb);
|
||||
@@ -562,8 +564,6 @@ test_profile_transfer()
|
||||
CHECK(dawn::profile_transfer(g18.get()) == dawn::Transfer::Srgb);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
||||
@@ -30,10 +30,7 @@ namespace fs = filesystem;
|
||||
#error DAWN_TEST_FIXTURES_DIR must be defined
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
dawn::ImagePtr
|
||||
static dawn::ImagePtr
|
||||
load(const char *name, const vector<string> &loaders, shared_ptr<dawn::Cmm> cmm,
|
||||
shared_ptr<dawn::Profile> screen)
|
||||
{
|
||||
@@ -53,7 +50,7 @@ load(const char *name, const vector<string> &loaders, shared_ptr<dawn::Cmm> cmm,
|
||||
|
||||
// Compares the ImageIO decoding of a fixture against its default one,
|
||||
// which is whatever loader the table would normally pick for it.
|
||||
dawn::ImagePtr
|
||||
static dawn::ImagePtr
|
||||
compare(const char *name, int tolerance, shared_ptr<dawn::Profile> screen)
|
||||
{
|
||||
auto cmm = dawn::Cmm::get_default();
|
||||
@@ -101,7 +98,7 @@ compare(const char *name, int tolerance, shared_ptr<dawn::Profile> screen)
|
||||
|
||||
// PNG decodes losslessly either way, so the identity path must be exact
|
||||
// but for premultiplication rounding.
|
||||
void
|
||||
static void
|
||||
test_solids()
|
||||
{
|
||||
constexpr int tolerance = 2 * 257;
|
||||
@@ -116,7 +113,7 @@ test_solids()
|
||||
|
||||
// Both loaders hand lcms2 the same embedded Display P3 profile, so both must
|
||||
// perform exactly one conversion into an AdobeRGB-like screen profile.
|
||||
void
|
||||
static void
|
||||
test_no_double_conversion()
|
||||
{
|
||||
auto cmm = dawn::Cmm::get_default();
|
||||
@@ -140,8 +137,6 @@ test_no_double_conversion()
|
||||
CHECK(!image->profile_assumed);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
||||
+34
-29
@@ -31,10 +31,10 @@
|
||||
using namespace std;
|
||||
namespace inst = dawn::ipc::instance;
|
||||
|
||||
#ifndef _WIN32
|
||||
namespace
|
||||
{
|
||||
|
||||
#ifndef _WIN32
|
||||
struct SocketPair {
|
||||
int fds[2] = {-1, -1};
|
||||
|
||||
@@ -53,7 +53,9 @@ struct SocketPair {
|
||||
explicit operator bool() const { return fds[0] >= 0; }
|
||||
};
|
||||
|
||||
bool
|
||||
} // namespace
|
||||
|
||||
static bool
|
||||
write_all(int fd, const void *p, size_t n)
|
||||
{
|
||||
const auto *b = static_cast<const uint8_t *>(p);
|
||||
@@ -72,7 +74,7 @@ write_all(int fd, const void *p, size_t n)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
put_u32be(uint8_t *out, uint32_t n)
|
||||
{
|
||||
out[0] = uint8_t((n >> 24) & 0xff);
|
||||
@@ -83,7 +85,7 @@ put_u32be(uint8_t *out, uint32_t n)
|
||||
|
||||
#endif
|
||||
|
||||
bool
|
||||
static bool
|
||||
payload_eq(const vector<byte> &got, span<const uint8_t> want)
|
||||
{
|
||||
if (got.size() != want.size())
|
||||
@@ -96,7 +98,7 @@ payload_eq(const vector<byte> &got, span<const uint8_t> want)
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void
|
||||
static void
|
||||
test_fragmented()
|
||||
{
|
||||
SocketPair pair;
|
||||
@@ -125,7 +127,7 @@ test_fragmented()
|
||||
CHECK(payload_eq(got, kPayload));
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_two_frames_one_write()
|
||||
{
|
||||
SocketPair pair;
|
||||
@@ -155,7 +157,7 @@ test_two_frames_one_write()
|
||||
CHECK(payload_eq(second, kB));
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_empty_payload()
|
||||
{
|
||||
SocketPair pair;
|
||||
@@ -171,7 +173,7 @@ test_empty_payload()
|
||||
CHECK(conn.read() == dawn::ipc::Connection::Status::Error);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_oversize_length()
|
||||
{
|
||||
SocketPair pair;
|
||||
@@ -187,7 +189,7 @@ test_oversize_length()
|
||||
CHECK(conn.read() == dawn::ipc::Connection::Status::Error);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_write_read_pair()
|
||||
{
|
||||
SocketPair pair;
|
||||
@@ -216,7 +218,7 @@ test_write_read_pair()
|
||||
// on, and neither half is exercised by the loopback tests above.
|
||||
constexpr char kService[] = "test";
|
||||
|
||||
void
|
||||
static void
|
||||
test_listen_arbitrates()
|
||||
{
|
||||
auto first = dawn::ipc::Endpoint::listen(kService);
|
||||
@@ -229,7 +231,7 @@ test_listen_arbitrates()
|
||||
CHECK(second.status == dawn::ipc::Endpoint::ListenStatus::InUse);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_endpoint_roundtrip()
|
||||
{
|
||||
auto listen = dawn::ipc::Endpoint::listen(kService);
|
||||
@@ -284,7 +286,7 @@ constexpr char kInstanceService[] = "test-instance";
|
||||
constexpr char kSession[] = "test-session";
|
||||
constexpr uint32_t kMaxPayload = 4096;
|
||||
|
||||
vector<byte>
|
||||
static vector<byte>
|
||||
frame_bytes(const inst::Frame &frame)
|
||||
{
|
||||
vector<byte> buf;
|
||||
@@ -294,7 +296,7 @@ frame_bytes(const inst::Frame &frame)
|
||||
return buf;
|
||||
}
|
||||
|
||||
inst::Frame
|
||||
static inst::Frame
|
||||
hello_frame(uint32_t version, string_view session)
|
||||
{
|
||||
inst::Hello hello;
|
||||
@@ -305,7 +307,7 @@ hello_frame(uint32_t version, string_view session)
|
||||
return frame;
|
||||
}
|
||||
|
||||
inst::Frame
|
||||
static inst::Frame
|
||||
open_frame(uint64_t id)
|
||||
{
|
||||
inst::OpenRequest open;
|
||||
@@ -318,7 +320,7 @@ open_frame(uint64_t id)
|
||||
return frame;
|
||||
}
|
||||
|
||||
inst::Frame
|
||||
static inst::Frame
|
||||
cancel_frame(uint64_t id)
|
||||
{
|
||||
inst::Frame frame;
|
||||
@@ -329,6 +331,9 @@ cancel_frame(uint64_t id)
|
||||
// A server, and one raw connection standing in for a client. Everything is
|
||||
// single-threaded: the peer writes, then pump() runs the server by hand
|
||||
// until an answer comes back.
|
||||
namespace
|
||||
{
|
||||
|
||||
struct Fixture {
|
||||
unique_ptr<inst::Server> server;
|
||||
dawn::ipc::Connection peer;
|
||||
@@ -345,6 +350,8 @@ struct Fixture {
|
||||
void poll();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void
|
||||
Fixture::poll()
|
||||
{
|
||||
@@ -438,7 +445,7 @@ Fixture::closed()
|
||||
}
|
||||
|
||||
// Complete the handshake, and report the payload limit it settled on.
|
||||
bool
|
||||
static bool
|
||||
handshake(Fixture &f, uint32_t &limit)
|
||||
{
|
||||
if (!f.send(
|
||||
@@ -461,7 +468,7 @@ handshake(Fixture &f, uint32_t &limit)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_handshake()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -486,7 +493,7 @@ test_instance_handshake()
|
||||
CHECK(f.requests == 1);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_version_mismatch()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -514,7 +521,7 @@ test_instance_version_mismatch()
|
||||
CHECK(f.closed());
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_session_mismatch()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -536,7 +543,7 @@ test_instance_session_mismatch()
|
||||
CHECK(f.closed());
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_request_before_hello()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -550,7 +557,7 @@ test_instance_request_before_hello()
|
||||
CHECK(f.requests == 0);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_zero_id()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -564,7 +571,7 @@ test_instance_zero_id()
|
||||
CHECK(f.requests == 0);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_duplicate_id()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -590,7 +597,7 @@ test_instance_duplicate_id()
|
||||
CHECK(held[0].cancelled());
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_out_of_order()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -646,7 +653,7 @@ test_instance_out_of_order()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_cancel()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -693,7 +700,7 @@ test_instance_cancel()
|
||||
CHECK(err->error.code == inst::ErrorCode::Cancelled);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_cancel_unknown()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -711,7 +718,7 @@ test_instance_cancel_unknown()
|
||||
CHECK(holds_alternative<inst::PayloadResponseView>(view.payload.value));
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_dropped_call()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -739,7 +746,7 @@ test_instance_dropped_call()
|
||||
CHECK(err->error.code == inst::ErrorCode::Internal);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_instance_oversize()
|
||||
{
|
||||
Fixture f;
|
||||
@@ -767,8 +774,6 @@ test_instance_oversize()
|
||||
CHECK(f.requests == 0);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
||||
+13
-18
@@ -22,11 +22,8 @@
|
||||
using namespace std;
|
||||
namespace inst = dawn::ipc::instance;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
vector<byte>
|
||||
static vector<byte>
|
||||
encoded(const T &value)
|
||||
{
|
||||
vector<byte> buf;
|
||||
@@ -36,7 +33,7 @@ encoded(const T &value)
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
bytes_eq(span<const byte> got, span<const uint8_t> want)
|
||||
{
|
||||
if (got.size() != want.size())
|
||||
@@ -48,7 +45,7 @@ bytes_eq(span<const byte> got, span<const uint8_t> want)
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
check_golden(
|
||||
const char *label, const vector<byte> &got, span<const uint8_t> want)
|
||||
{
|
||||
@@ -61,7 +58,7 @@ check_golden(
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_round_trip_hello_reply()
|
||||
{
|
||||
{
|
||||
@@ -102,7 +99,7 @@ test_round_trip_hello_reply()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_round_trip_result()
|
||||
{
|
||||
{
|
||||
@@ -131,7 +128,7 @@ test_round_trip_result()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_round_trip_frames()
|
||||
{
|
||||
{
|
||||
@@ -248,7 +245,7 @@ test_round_trip_frames()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_goldens()
|
||||
{
|
||||
// Hello{1, "b"}: u32be version, u32be len+"b"
|
||||
@@ -285,7 +282,7 @@ test_goldens()
|
||||
encoded(inst::Error{inst::ErrorCode::NotFound, "x"}), kError);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_truncation()
|
||||
{
|
||||
const vector<byte> full = encoded(inst::Hello{1, "b"});
|
||||
@@ -306,7 +303,7 @@ test_truncation()
|
||||
CHECK(view.session == "b");
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_trailing_bytes()
|
||||
{
|
||||
vector<byte> buf = encoded(inst::Hello{1, "b"});
|
||||
@@ -319,7 +316,7 @@ test_trailing_bytes()
|
||||
CHECK(!ok || dec.remaining() != 0);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_invalid_utf8()
|
||||
{
|
||||
{
|
||||
@@ -340,7 +337,7 @@ test_invalid_utf8()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_zero_and_unknown_enum()
|
||||
{
|
||||
for (byte tag : {byte{0}, byte{99}}) {
|
||||
@@ -351,7 +348,7 @@ test_zero_and_unknown_enum()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_unknown_union_tag()
|
||||
{
|
||||
const byte raw[] = {byte{99}};
|
||||
@@ -360,7 +357,7 @@ test_unknown_union_tag()
|
||||
CHECK(!decode(dec, view));
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_huge_array_count()
|
||||
{
|
||||
const size_t n = dawn::ipc::Decoder::kMaxElements + 1;
|
||||
@@ -390,8 +387,6 @@ test_huge_array_count()
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
||||
@@ -45,7 +45,9 @@ struct WorkGate {
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
} // namespace
|
||||
|
||||
static bool
|
||||
test_background_reserve()
|
||||
{
|
||||
dn::Thumbnailer thumbnailer(nullptr, 4);
|
||||
@@ -102,7 +104,7 @@ test_background_reserve()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
test_visible_reserve()
|
||||
{
|
||||
dn::Thumbnailer thumbnailer(nullptr, 4);
|
||||
@@ -153,7 +155,7 @@ test_visible_reserve()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
test_reprioritization_order()
|
||||
{
|
||||
dn::Thumbnailer thumbnailer(nullptr, 1);
|
||||
@@ -212,7 +214,7 @@ test_reprioritization_order()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
static bool
|
||||
test_bundle_reservations()
|
||||
{
|
||||
dn::Thumbnailer thumbnailer(nullptr, 2);
|
||||
@@ -246,7 +248,7 @@ test_bundle_reservations()
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
test_activity_transitions(QCoreApplication &app)
|
||||
{
|
||||
dn::Thumbnailer thumbnailer;
|
||||
@@ -282,8 +284,6 @@ test_activity_transitions(QCoreApplication &app)
|
||||
CHECK(saw_idle);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user