transport in rgba order
so if core is compiled with a cairo using rgba the pixels can be sent without need to reorder in server or client Signed-off-by: Caolán McNamara <caolan.mcnamara@collabora.com> Change-Id: Iaf0410f1eaa605b9ce2716625f6c968bca523ccb
This commit is contained in:
parent
01165fbe1f
commit
76a5a9baff
5 changed files with 86 additions and 46 deletions
|
@ -6742,36 +6742,24 @@ L.CanvasTileLayer = L.Layer.extend({
|
|||
return ctx;
|
||||
},
|
||||
|
||||
_brgatorgba: function(rawDelta) {
|
||||
_unpremultiply: function(rawDelta) {
|
||||
var len = rawDelta.byteLength / 4;
|
||||
var delta32 = new Uint32Array(rawDelta.buffer, rawDelta.byteOffset, len);
|
||||
var resultu32 = new Uint32Array(len);
|
||||
var resultu8 = new Uint8ClampedArray(resultu32.buffer, resultu32.byteOffset, resultu32.byteLength);
|
||||
for (var i32 = 0; i32 < len; ++i32) {
|
||||
// premultiplied brga -> unpremultiplied rgba
|
||||
// If the previous input pixel was the same as the current input pixel
|
||||
// just copy the previous output pixel as the current output pixel
|
||||
if (i32 > 0 && delta32[i32] === delta32[i32 - 1])
|
||||
resultu32[i32] = resultu32[i32 - 1];
|
||||
else
|
||||
{
|
||||
// premultiplied rgba -> unpremultiplied rgba
|
||||
var alpha = delta32[i32] >>> 24;
|
||||
if (alpha === 255) {
|
||||
resultu32[i32] = delta32[i32];
|
||||
}
|
||||
else if (alpha !== 0) { // dest can remain at ctored 0 if alpha is 0
|
||||
var i8 = i32 * 4;
|
||||
var alpha = rawDelta[i8 + 3];
|
||||
if (alpha === 255) {
|
||||
resultu8[i8] = rawDelta[i8 + 2];
|
||||
resultu8[i8 + 1] = rawDelta[i8 + 1];
|
||||
resultu8[i8 + 2] = rawDelta[i8];
|
||||
resultu8[i8 + 3] = 255;
|
||||
}
|
||||
else if (alpha === 0)
|
||||
resultu32[i32] = 0;
|
||||
else // forced to do the math
|
||||
{
|
||||
resultu8[i8] = Math.ceil(rawDelta[i8 + 2] * 255 / alpha);
|
||||
resultu8[i8 + 1] = Math.ceil(rawDelta[i8 + 1] * 255 / alpha);
|
||||
resultu8[i8 + 2] = Math.ceil(rawDelta[i8] * 255 / alpha);
|
||||
resultu8[i8 + 3] = alpha;
|
||||
}
|
||||
// forced to do the math
|
||||
resultu8[i8] = Math.ceil(rawDelta[i8] * 255 / alpha);
|
||||
resultu8[i8 + 1] = Math.ceil(rawDelta[i8 + 1] * 255 / alpha);
|
||||
resultu8[i8 + 2] = Math.ceil(rawDelta[i8 + 2] * 255 / alpha);
|
||||
resultu8[i8 + 3] = alpha;
|
||||
}
|
||||
}
|
||||
return resultu8;
|
||||
|
@ -6853,7 +6841,7 @@ L.CanvasTileLayer = L.Layer.extend({
|
|||
{
|
||||
// FIXME: use zstd to de-compress directly into a Uint8ClampedArray
|
||||
len = canvas.width * canvas.height * 4;
|
||||
var pixelArray = this._brgatorgba(delta.subarray(0, len));
|
||||
var pixelArray = this._unpremultiply(delta.subarray(0, len));
|
||||
imgData = new ImageData(pixelArray, canvas.width, canvas.height);
|
||||
|
||||
if (this._debugDeltas)
|
||||
|
@ -6953,7 +6941,7 @@ L.CanvasTileLayer = L.Layer.extend({
|
|||
span *= 4;
|
||||
// copy so this is suitably aligned for a Uint32Array view
|
||||
var tmpu8 = new Uint8Array(delta.subarray(i, i + span));
|
||||
var pixelData = this._brgatorgba(tmpu8);
|
||||
var pixelData = this._unpremultiply(tmpu8);
|
||||
// imgData.data[offset + 1] = 256; // debug - greener start
|
||||
for (var j = 0; j < span; ++j)
|
||||
imgData.data[offset++] = pixelData[j];
|
||||
|
|
|
@ -80,9 +80,9 @@ extern "C"
|
|||
}
|
||||
|
||||
|
||||
/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
|
||||
/* Unpremultiplies data and converts native endian BGRA => RGBA bytes */
|
||||
static void
|
||||
unpremultiply_data (png_structp /*png*/, png_row_infop row_info, png_bytep data)
|
||||
unpremultiply_bgra_data (png_structp /*png*/, png_row_infop row_info, png_bytep data)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
@ -116,6 +116,40 @@ unpremultiply_data (png_structp /*png*/, png_row_infop row_info, png_bytep data)
|
|||
}
|
||||
}
|
||||
|
||||
/* Unpremultiplies data already in RGBA order*/
|
||||
static void
|
||||
unpremultiply_rgba_data (png_structp /*png*/, png_row_infop row_info, png_bytep data)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < row_info->rowbytes; i += 4)
|
||||
{
|
||||
uint8_t *b = &data[i];
|
||||
uint32_t pix;
|
||||
uint8_t alpha;
|
||||
|
||||
std::memcpy (&pix, b, sizeof (uint32_t));
|
||||
|
||||
alpha = (pix & 0xff000000) >> 24;
|
||||
if (alpha == 255)
|
||||
{
|
||||
std::memcpy(b, &pix, sizeof (uint32_t));
|
||||
}
|
||||
else if (alpha == 0)
|
||||
{
|
||||
b[0] = b[1] = b[2] = b[3] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
b[0] = (((pix & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
|
||||
b[1] = (((pix & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
|
||||
b[2] = (((pix & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
|
||||
b[3] = alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// This function uses setjmp which may clobbers non-trivial objects.
|
||||
/// So we can't use logging or create complex C++ objects in this frame.
|
||||
/// Specifically, logging uses std::string objects, and GCC gives the following:
|
||||
|
@ -161,9 +195,14 @@ inline bool impl_encodeSubBufferToPNG(unsigned char* pixmap, size_t startX, size
|
|||
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
if (mode == LOK_TILEMODE_BGRA)
|
||||
switch (mode)
|
||||
{
|
||||
png_set_write_user_transform_fn (png_ptr, unpremultiply_data);
|
||||
case LOK_TILEMODE_BGRA:
|
||||
png_set_write_user_transform_fn (png_ptr, unpremultiply_bgra_data);
|
||||
break;
|
||||
case LOK_TILEMODE_RGBA:
|
||||
png_set_write_user_transform_fn (png_ptr, unpremultiply_rgba_data);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int y = 0; y < height; ++y)
|
||||
|
|
|
@ -146,7 +146,8 @@ class DeltaGenerator {
|
|||
// Create a diff from our state to new state in curRow
|
||||
void diffRowTo(const DeltaBitmapRow &curRow,
|
||||
const int width, const int curY,
|
||||
std::vector<uint8_t> &output) const
|
||||
std::vector<uint8_t> &output,
|
||||
LibreOfficeKitTileMode mode) const
|
||||
{
|
||||
PixIterator oldPixels(*this);
|
||||
PixIterator curPixels(curRow);
|
||||
|
@ -188,7 +189,7 @@ class DeltaGenerator {
|
|||
|
||||
copy_row(reinterpret_cast<unsigned char *>(&output[dest]),
|
||||
(const unsigned char *)(scratch),
|
||||
diff);
|
||||
diff, mode);
|
||||
|
||||
LOG_TRC("row " << curY << " different " << diff << "pixels");
|
||||
x += diff;
|
||||
|
@ -352,15 +353,26 @@ class DeltaGenerator {
|
|||
}
|
||||
|
||||
static void
|
||||
copy_row (unsigned char *dest, const unsigned char *srcBytes, unsigned int count)
|
||||
copy_row (unsigned char *dest, const unsigned char *srcBytes, unsigned int count, LibreOfficeKitTileMode mode)
|
||||
{
|
||||
std::memcpy(dest, srcBytes, count * 4);
|
||||
switch (mode)
|
||||
{
|
||||
case LOK_TILEMODE_RGBA:
|
||||
std::memcpy(dest, srcBytes, count * 4);
|
||||
break;
|
||||
case LOK_TILEMODE_BGRA:
|
||||
std::memcpy(dest, srcBytes, count * 4);
|
||||
for (size_t j = 0; j < count * 4; j += 4)
|
||||
std::swap(dest[j], dest[j+2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool makeDelta(
|
||||
const DeltaData &prev,
|
||||
const DeltaData &cur,
|
||||
std::vector<char>& outStream)
|
||||
std::vector<char>& outStream,
|
||||
LibreOfficeKitTileMode mode)
|
||||
{
|
||||
// TODO: should we split and compress alpha separately ?
|
||||
if (prev.getWidth() != cur.getWidth() || prev.getHeight() != cur.getHeight())
|
||||
|
@ -430,7 +442,7 @@ class DeltaGenerator {
|
|||
continue;
|
||||
|
||||
// Our row is just that different:
|
||||
prev.getRow(y).diffRowTo(cur.getRow(y), prev.getWidth(), y, output);
|
||||
prev.getRow(y).diffRowTo(cur.getRow(y), prev.getWidth(), y, output, mode);
|
||||
}
|
||||
LOG_TRC("Created delta of size " << output.size());
|
||||
if (output.empty())
|
||||
|
@ -520,7 +532,8 @@ class DeltaGenerator {
|
|||
int bufferWidth, int bufferHeight,
|
||||
const TileLocation &loc,
|
||||
std::vector<char>& output,
|
||||
TileWireId wid, bool forceKeyframe)
|
||||
TileWireId wid, bool forceKeyframe,
|
||||
LibreOfficeKitTileMode mode)
|
||||
{
|
||||
if ((width & 0x1) != 0) // power of two - RGBA
|
||||
{
|
||||
|
@ -557,7 +570,7 @@ class DeltaGenerator {
|
|||
|
||||
bool delta = false;
|
||||
if (!forceKeyframe)
|
||||
delta = makeDelta(*cacheEntry, *update, output);
|
||||
delta = makeDelta(*cacheEntry, *update, output, mode);
|
||||
|
||||
// no two threads can be working on the same DeltaData.
|
||||
cacheEntry->replaceAndFree(update);
|
||||
|
@ -629,7 +642,7 @@ class DeltaGenerator {
|
|||
|
||||
if (!createDelta(pixmap, startX, startY, width, height,
|
||||
bufferWidth, bufferHeight,
|
||||
loc, output, wid, forceKeyframe))
|
||||
loc, output, wid, forceKeyframe, mode))
|
||||
{
|
||||
// FIXME: should stream it in =)
|
||||
size_t maxCompressed = ZSTD_COMPRESSBOUND((size_t)width * height * 4);
|
||||
|
@ -655,7 +668,7 @@ class DeltaGenerator {
|
|||
// FIXME: should we RLE in pixels first ?
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
copy_row(fixedupLine, pixmap + ((startY + y) * bufferWidth * 4) + (startX * 4), width);
|
||||
copy_row(fixedupLine, pixmap + ((startY + y) * bufferWidth * 4) + (startX * 4), width, mode);
|
||||
|
||||
ZSTD_inBuffer inb;
|
||||
inb.src = fixedupLine;
|
||||
|
|
|
@ -357,7 +357,7 @@ static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
|
|||
|
||||
static int doc_getTileMode(LibreOfficeKitDocument* /*pThis*/)
|
||||
{
|
||||
return LOK_TILEMODE_BGRA;
|
||||
return LOK_TILEMODE_RGBA;
|
||||
}
|
||||
|
||||
static void doc_getDocumentSize(LibreOfficeKitDocument* pThis,
|
||||
|
|
|
@ -399,14 +399,14 @@ void DeltaTests::testDeltaSequence()
|
|||
LOK_ASSERT(gen.createDelta(
|
||||
reinterpret_cast<unsigned char *>(&text[0]),
|
||||
0, 0, width, height, width, height,
|
||||
TileLocation(1, 2, 3, 0, 1), delta, textWid, false) == false);
|
||||
TileLocation(1, 2, 3, 0, 1), delta, textWid, false, LOK_TILEMODE_RGBA) == false);
|
||||
LOK_ASSERT(delta.empty());
|
||||
|
||||
// Build a delta between text2 & textWid
|
||||
LOK_ASSERT(gen.createDelta(
|
||||
reinterpret_cast<unsigned char *>(&text2[0]),
|
||||
0, 0, width, height, width, height,
|
||||
TileLocation(1, 2, 3, 0, 1), delta, text2Wid, false) == true);
|
||||
TileLocation(1, 2, 3, 0, 1), delta, text2Wid, false, LOK_TILEMODE_RGBA) == true);
|
||||
LOK_ASSERT(delta.size() > 0);
|
||||
checkzDelta(delta, "text2 to textWid");
|
||||
|
||||
|
@ -419,7 +419,7 @@ void DeltaTests::testDeltaSequence()
|
|||
LOK_ASSERT(gen.createDelta(
|
||||
reinterpret_cast<unsigned char *>(&text[0]),
|
||||
0, 0, width, height, width, height,
|
||||
TileLocation(1, 2, 3, 0, 1), two2one, textWid, false) == true);
|
||||
TileLocation(1, 2, 3, 0, 1), two2one, textWid, false, LOK_TILEMODE_RGBA) == true);
|
||||
LOK_ASSERT(two2one.size() > 0);
|
||||
checkzDelta(two2one, "text to text2Wid");
|
||||
|
||||
|
@ -458,14 +458,14 @@ void DeltaTests::testDeltaCopyOutOfBounds()
|
|||
LOK_ASSERT(gen.createDelta(
|
||||
reinterpret_cast<unsigned char *>(&text[0]),
|
||||
0, 0, width, height, width, height,
|
||||
TileLocation(1, 2, 3, 0, 1), delta, textWid, false) == false);
|
||||
TileLocation(1, 2, 3, 0, 1), delta, textWid, false, LOK_TILEMODE_RGBA) == false);
|
||||
LOK_ASSERT(delta.empty());
|
||||
|
||||
// Build a delta between the two frames
|
||||
LOK_ASSERT(gen.createDelta(
|
||||
reinterpret_cast<unsigned char *>(&text2[0]),
|
||||
0, 0, width, height, width, height,
|
||||
TileLocation(1, 2, 3, 0, 1), delta, text2Wid, false) == true);
|
||||
TileLocation(1, 2, 3, 0, 1), delta, text2Wid, false, LOK_TILEMODE_RGBA) == true);
|
||||
LOK_ASSERT(delta.size() > 0);
|
||||
checkzDelta(delta, "copy out of bounds");
|
||||
|
||||
|
|
Loading…
Reference in a new issue