palette.c 17.3 KB
Newer Older
1 2
/*
 * Copyright 2009 Vincent Povirk for CodeWeavers
3
 * Copyright 2012 Dmitry Timoshkov
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"

#include <stdarg.h>

#define COBJMACROS

#include "windef.h"
#include "winbase.h"
#include "winreg.h"
#include "objbase.h"

#include "wincodecs_private.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);

typedef struct {
38
    IWICPalette IWICPalette_iface;
39
    LONG ref;
40 41 42
    UINT count;
    WICColor *colors;
    WICBitmapPaletteType type;
43
    CRITICAL_SECTION lock; /* must be held when count, colors, or type is accessed */
44 45
} PaletteImpl;

46 47 48 49 50
static inline PaletteImpl *impl_from_IWICPalette(IWICPalette *iface)
{
    return CONTAINING_RECORD(iface, PaletteImpl, IWICPalette_iface);
}

51 52 53
static HRESULT WINAPI PaletteImpl_QueryInterface(IWICPalette *iface, REFIID iid,
    void **ppv)
{
54
    PaletteImpl *This = impl_from_IWICPalette(iface);
55 56 57 58 59 60
    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);

    if (!ppv) return E_INVALIDARG;

    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICPalette, iid))
    {
61
        *ppv = &This->IWICPalette_iface;
62 63 64 65 66 67 68 69 70 71 72 73 74
    }
    else
    {
        *ppv = NULL;
        return E_NOINTERFACE;
    }

    IUnknown_AddRef((IUnknown*)*ppv);
    return S_OK;
}

static ULONG WINAPI PaletteImpl_AddRef(IWICPalette *iface)
{
75
    PaletteImpl *This = impl_from_IWICPalette(iface);
76 77 78 79 80 81 82 83 84
    ULONG ref = InterlockedIncrement(&This->ref);

    TRACE("(%p) refcount=%u\n", iface, ref);

    return ref;
}

static ULONG WINAPI PaletteImpl_Release(IWICPalette *iface)
{
85
    PaletteImpl *This = impl_from_IWICPalette(iface);
86 87 88 89 90
    ULONG ref = InterlockedDecrement(&This->ref);

    TRACE("(%p) refcount=%u\n", iface, ref);

    if (ref == 0)
91
    {
92 93
        This->lock.DebugInfo->Spare[0] = 0;
        DeleteCriticalSection(&This->lock);
94
        HeapFree(GetProcessHeap(), 0, This->colors);
95
        HeapFree(GetProcessHeap(), 0, This);
96
    }
97 98 99 100

    return ref;
}

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
static WICColor *generate_gray16_palette(UINT *count)
{
    WICColor *entries;
    UINT i;

    *count = 16;
    entries = HeapAlloc(GetProcessHeap(), 0, 16 * sizeof(WICColor));
    if (!entries) return NULL;

    for (i = 0; i < 16; i++)
    {
        entries[i] = 0xff000000;
        entries[i] |= (i<<20) | (i<<16) | (i<<12) | (i<<8) | (i<<4) | i;
    }
    return entries;
}

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
static WICColor *generate_gray256_palette(UINT *count)
{
    WICColor *entries;
    UINT i;

    *count = 256;
    entries = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WICColor));
    if (!entries) return NULL;

    for (i = 0; i < 256; i++)
    {
        entries[i] = 0xff000000;
        entries[i] |= (i<<16) | (i<<8) | i;
    }
    return entries;
}

135
static WICColor *generate_halftone8_palette(UINT *count, BOOL add_transparent)
136 137 138 139
{
    WICColor *entries;
    UINT i;

140 141
    *count = add_transparent ? 17 : 16;
    entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
    if (!entries) return NULL;

    for (i = 0; i < 8; i++)
    {
        entries[i] = 0xff000000;
        if (i & 1) entries[i] |= 0xff;
        if (i & 2) entries[i] |= 0xff00;
        if (i & 4) entries[i] |= 0xff0000;
    }

    for (i = 8; i < 16; i++)
    {
        static const DWORD halftone[8] = { 0xc0c0c0, 0x808080, 0x800000, 0x008000,
                                           0x000080, 0x808000, 0x800080, 0x008080 };
        entries[i] = 0xff000000;
        entries[i] |= halftone[i-8];
    }
159 160 161 162

    if (add_transparent)
        entries[i] = 0;

163 164 165
    return entries;
}

166
static WICColor *generate_halftone27_palette(UINT *count, BOOL add_transparent)
167 168 169 170
{
    WICColor *entries;
    UINT i;

171 172
    *count = add_transparent ? 29 : 28;
    entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
173 174 175 176 177 178 179 180 181 182 183
    if (!entries) return NULL;

    for (i = 0; i < 27; i++)
    {
        static const BYTE halftone_values[4] = { 0x00,0x80,0xff };
        entries[i] = 0xff000000;
        entries[i] |= halftone_values[i%3];
        entries[i] |= halftone_values[(i/3)%3] << 8;
        entries[i] |= halftone_values[(i/9)%3] << 16;
    }

184 185 186 187
    entries[i++] = 0xffc0c0c0;
    if (add_transparent)
        entries[i] = 0;

188 189 190
    return entries;
}

191
static WICColor *generate_halftone64_palette(UINT *count, BOOL add_transparent)
192 193 194 195
{
    WICColor *entries;
    UINT i;

196 197
    *count = add_transparent ? 73 : 72;
    entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
    if (!entries) return NULL;

    for (i = 0; i < 64; i++)
    {
        static const BYTE halftone_values[4] = { 0x00,0x55,0xaa,0xff };
        entries[i] = 0xff000000;
        entries[i] |= halftone_values[i%4];
        entries[i] |= halftone_values[(i/4)%4] << 8;
        entries[i] |= halftone_values[(i/16)%4] << 16;
    }

    for (i = 64; i < 72; i++)
    {
        static const DWORD halftone[8] = { 0xc0c0c0, 0x808080, 0x800000, 0x008000,
                                           0x000080, 0x808000, 0x800080, 0x008080 };
        entries[i] = 0xff000000;
        entries[i] |= halftone[i-64];
    }
216 217 218 219

    if (add_transparent)
        entries[i] = 0;

220 221 222
    return entries;
}

223
static WICColor *generate_halftone125_palette(UINT *count, BOOL add_transparent)
224 225 226 227
{
    WICColor *entries;
    UINT i;

228 229
    *count = add_transparent ? 127 : 126;
    entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
230 231 232 233 234 235 236 237 238 239 240
    if (!entries) return NULL;

    for (i = 0; i < 125; i++)
    {
        static const BYTE halftone_values[5] = { 0x00,0x40,0x80,0xbf,0xff };
        entries[i] = 0xff000000;
        entries[i] |= halftone_values[i%5];
        entries[i] |= halftone_values[(i/5)%5] << 8;
        entries[i] |= halftone_values[(i/25)%5] << 16;
    }

241 242 243 244
    entries[i++] = 0xffc0c0c0;
    if (add_transparent)
        entries[i] = 0;

245 246 247
    return entries;
}

248
static WICColor *generate_halftone216_palette(UINT *count, BOOL add_transparent)
249 250 251 252
{
    WICColor *entries;
    UINT i;

253 254
    *count = add_transparent ? 225 : 224;
    entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
    if (!entries) return NULL;

    for (i = 0; i < 216; i++)
    {
        static const BYTE halftone_values[6] = { 0x00,0x33,0x66,0x99,0xcc,0xff };
        entries[i] = 0xff000000;
        entries[i] |= halftone_values[i%6];
        entries[i] |= halftone_values[(i/6)%6] << 8;
        entries[i] |= halftone_values[(i/36)%6] << 16;
    }

    for (i = 216; i < 224; i++)
    {
        static const DWORD halftone[8] = { 0xc0c0c0, 0x808080, 0x800000, 0x008000,
                                           0x000080, 0x808000, 0x800080, 0x008080 };
        entries[i] = 0xff000000;
        entries[i] |= halftone[i-216];
    }
273 274 275 276

    if (add_transparent)
        entries[i] = 0;

277 278 279
    return entries;
}

280
static WICColor *generate_halftone252_palette(UINT *count, BOOL add_transparent)
281 282 283 284
{
    WICColor *entries;
    UINT i;

285 286
    *count = add_transparent ? 253 : 252;
    entries = HeapAlloc(GetProcessHeap(), 0, *count * sizeof(WICColor));
287 288 289 290 291 292 293 294 295 296 297
    if (!entries) return NULL;

    for (i = 0; i < 252; i++)
    {
        static const BYTE halftone_values_rb[6] = { 0x00,0x33,0x66,0x99,0xcc,0xff };
        static const BYTE halftone_values_g[7] = { 0x00,0x2b,0x55,0x80,0xaa,0xd5,0xff };
        entries[i] = 0xff000000;
        entries[i] |= halftone_values_rb[i%6];
        entries[i] |= halftone_values_g[(i/6)%7] << 8;
        entries[i] |= halftone_values_rb[(i/42)%6] << 16;
    }
298 299 300 301

    if (add_transparent)
        entries[i] = 0;

302 303 304
    return entries;
}

305
static WICColor *generate_halftone256_palette(UINT *count, BOOL add_transparent)
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
{
    WICColor *entries;
    UINT i;

    *count = 256;
    entries = HeapAlloc(GetProcessHeap(), 0, 256 * sizeof(WICColor));
    if (!entries) return NULL;

    for (i = 0; i < 256; i++)
    {
        static const BYTE halftone_values_b[4] = { 0x00,0x55,0xaa,0xff };
        static const BYTE halftone_values_gr[8] = { 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff };
        entries[i] = 0xff000000;
        entries[i] |= halftone_values_b[i%4];
        entries[i] |= halftone_values_gr[(i/4)%8] << 8;
        entries[i] |= halftone_values_gr[(i/32)%8] << 16;
    }
323 324 325 326

    if (add_transparent)
        entries[255] = 0;

327 328 329
    return entries;
}

330
static HRESULT WINAPI PaletteImpl_InitializePredefined(IWICPalette *iface,
331
    WICBitmapPaletteType type, BOOL add_transparent)
332
{
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348
    PaletteImpl *This = impl_from_IWICPalette(iface);
    WICColor *colors;
    UINT count;

    TRACE("(%p,%u,%d)\n", iface, type, add_transparent);

    switch (type)
    {
    case WICBitmapPaletteTypeFixedBW:
        count = 2;
        colors = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WICColor));
        if (!colors) return E_OUTOFMEMORY;
        colors[0] = 0xff000000;
        colors[1] = 0xffffffff;
        break;

349 350 351 352 353 354 355 356 357 358
    case WICBitmapPaletteTypeFixedGray4:
        count = 4;
        colors = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WICColor));
        if (!colors) return E_OUTOFMEMORY;
        colors[0] = 0xff000000;
        colors[1] = 0xff555555;
        colors[2] = 0xffaaaaaa;
        colors[3] = 0xffffffff;
        break;

359 360 361 362 363
    case WICBitmapPaletteTypeFixedGray16:
        colors = generate_gray16_palette(&count);
        if (!colors) return E_OUTOFMEMORY;
        break;

364 365 366 367 368
    case WICBitmapPaletteTypeFixedGray256:
        colors = generate_gray256_palette(&count);
        if (!colors) return E_OUTOFMEMORY;
        break;

369
    case WICBitmapPaletteTypeFixedHalftone8:
370
        colors = generate_halftone8_palette(&count, add_transparent);
371 372 373
        if (!colors) return E_OUTOFMEMORY;
        break;

374
    case WICBitmapPaletteTypeFixedHalftone27:
375
        colors = generate_halftone27_palette(&count, add_transparent);
376 377 378
        if (!colors) return E_OUTOFMEMORY;
        break;

379
    case WICBitmapPaletteTypeFixedHalftone64:
380
        colors = generate_halftone64_palette(&count, add_transparent);
381 382 383
        if (!colors) return E_OUTOFMEMORY;
        break;

384
    case WICBitmapPaletteTypeFixedHalftone125:
385
        colors = generate_halftone125_palette(&count, add_transparent);
386 387 388
        if (!colors) return E_OUTOFMEMORY;
        break;

389
    case WICBitmapPaletteTypeFixedHalftone216:
390
        colors = generate_halftone216_palette(&count, add_transparent);
391 392 393
        if (!colors) return E_OUTOFMEMORY;
        break;

394
    case WICBitmapPaletteTypeFixedHalftone252:
395
        colors = generate_halftone252_palette(&count, add_transparent);
396 397 398
        if (!colors) return E_OUTOFMEMORY;
        break;

399
    case WICBitmapPaletteTypeFixedHalftone256:
400
        colors = generate_halftone256_palette(&count, add_transparent);
401 402 403
        if (!colors) return E_OUTOFMEMORY;
        break;

404
    default:
405 406
        WARN("invalid palette type %u\n", type);
        return E_INVALIDARG;
407 408 409 410 411 412 413 414 415 416
    }

    EnterCriticalSection(&This->lock);
    HeapFree(GetProcessHeap(), 0, This->colors);
    This->colors = colors;
    This->count = count;
    This->type = type;
    LeaveCriticalSection(&This->lock);

    return S_OK;
417 418 419 420 421
}

static HRESULT WINAPI PaletteImpl_InitializeCustom(IWICPalette *iface,
    WICColor *pColors, UINT colorCount)
{
422
    PaletteImpl *This = impl_from_IWICPalette(iface);
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
    WICColor *new_colors;

    TRACE("(%p,%p,%u)\n", iface, pColors, colorCount);

    if (colorCount == 0)
    {
        new_colors = NULL;
    }
    else
    {
        if (!pColors) return E_INVALIDARG;
        new_colors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * colorCount);
        if (!new_colors) return E_OUTOFMEMORY;
        memcpy(new_colors, pColors, sizeof(WICColor) * colorCount);
    }

439
    EnterCriticalSection(&This->lock);
440 441 442 443
    HeapFree(GetProcessHeap(), 0, This->colors);
    This->colors = new_colors;
    This->count = colorCount;
    This->type = WICBitmapPaletteTypeCustom;
444
    LeaveCriticalSection(&This->lock);
445 446

    return S_OK;
447 448 449 450 451 452 453 454 455 456
}

static HRESULT WINAPI PaletteImpl_InitializeFromBitmap(IWICPalette *iface,
    IWICBitmapSource *pISurface, UINT colorCount, BOOL fAddTransparentColor)
{
    FIXME("(%p,%p,%u,%i): stub\n", iface, pISurface, colorCount, fAddTransparentColor);
    return E_NOTIMPL;
}

static HRESULT WINAPI PaletteImpl_InitializeFromPalette(IWICPalette *iface,
457
    IWICPalette *source)
458
{
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
    PaletteImpl *This = impl_from_IWICPalette(iface);
    UINT count;
    WICColor *colors = NULL;
    WICBitmapPaletteType type;
    HRESULT hr;

    TRACE("(%p,%p)\n", iface, source);

    if (!source) return E_INVALIDARG;

    hr = IWICPalette_GetType(source, &type);
    if (hr != S_OK) return hr;
    hr = IWICPalette_GetColorCount(source, &count);
    if (hr != S_OK) return hr;
    if (count)
    {
        colors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * count);
        if (!colors) return E_OUTOFMEMORY;
        hr = IWICPalette_GetColors(source, count, colors, &count);
478 479 480 481 482
        if (hr != S_OK)
        {
            HeapFree(GetProcessHeap(), 0, colors);
            return hr;
        }
483 484 485 486 487 488 489 490 491 492
    }

    EnterCriticalSection(&This->lock);
    HeapFree(GetProcessHeap(), 0, This->colors);
    This->colors = colors;
    This->count = count;
    This->type = type;
    LeaveCriticalSection(&This->lock);

    return S_OK;
493 494 495 496 497
}

static HRESULT WINAPI PaletteImpl_GetType(IWICPalette *iface,
    WICBitmapPaletteType *pePaletteType)
{
498
    PaletteImpl *This = impl_from_IWICPalette(iface);
499 500 501 502 503

    TRACE("(%p,%p)\n", iface, pePaletteType);

    if (!pePaletteType) return E_INVALIDARG;

504
    EnterCriticalSection(&This->lock);
505
    *pePaletteType = This->type;
506
    LeaveCriticalSection(&This->lock);
507 508

    return S_OK;
509 510 511 512
}

static HRESULT WINAPI PaletteImpl_GetColorCount(IWICPalette *iface, UINT *pcCount)
{
513
    PaletteImpl *This = impl_from_IWICPalette(iface);
514 515 516 517 518

    TRACE("(%p,%p)\n", iface, pcCount);

    if (!pcCount) return E_INVALIDARG;

519
    EnterCriticalSection(&This->lock);
520
    *pcCount = This->count;
521
    LeaveCriticalSection(&This->lock);
522 523

    return S_OK;
524 525 526 527 528
}

static HRESULT WINAPI PaletteImpl_GetColors(IWICPalette *iface, UINT colorCount,
    WICColor *pColors, UINT *pcActualColors)
{
529
    PaletteImpl *This = impl_from_IWICPalette(iface);
530 531 532 533 534

    TRACE("(%p,%i,%p,%p)\n", iface, colorCount, pColors, pcActualColors);

    if (!pColors || !pcActualColors) return E_INVALIDARG;

535 536
    EnterCriticalSection(&This->lock);

537 538 539 540 541 542
    if (This->count < colorCount) colorCount = This->count;

    memcpy(pColors, This->colors, sizeof(WICColor) * colorCount);

    *pcActualColors = colorCount;

543 544
    LeaveCriticalSection(&This->lock);

545
    return S_OK;
546 547 548 549
}

static HRESULT WINAPI PaletteImpl_IsBlackWhite(IWICPalette *iface, BOOL *pfIsBlackWhite)
{
550
    PaletteImpl *This = impl_from_IWICPalette(iface);
551 552 553 554 555

    TRACE("(%p,%p)\n", iface, pfIsBlackWhite);

    if (!pfIsBlackWhite) return E_INVALIDARG;

556
    EnterCriticalSection(&This->lock);
557 558 559 560
    if (This->type == WICBitmapPaletteTypeFixedBW)
        *pfIsBlackWhite = TRUE;
    else
        *pfIsBlackWhite = FALSE;
561
    LeaveCriticalSection(&This->lock);
562 563

    return S_OK;
564 565 566 567
}

static HRESULT WINAPI PaletteImpl_IsGrayscale(IWICPalette *iface, BOOL *pfIsGrayscale)
{
568
    PaletteImpl *This = impl_from_IWICPalette(iface);
569 570 571 572 573

    TRACE("(%p,%p)\n", iface, pfIsGrayscale);

    if (!pfIsGrayscale) return E_INVALIDARG;

574
    EnterCriticalSection(&This->lock);
575 576 577 578 579 580 581 582 583 584 585
    switch(This->type)
    {
        case WICBitmapPaletteTypeFixedBW:
        case WICBitmapPaletteTypeFixedGray4:
        case WICBitmapPaletteTypeFixedGray16:
        case WICBitmapPaletteTypeFixedGray256:
            *pfIsGrayscale = TRUE;
            break;
        default:
            *pfIsGrayscale = FALSE;
    }
586
    LeaveCriticalSection(&This->lock);
587 588

    return S_OK;
589 590 591 592
}

static HRESULT WINAPI PaletteImpl_HasAlpha(IWICPalette *iface, BOOL *pfHasAlpha)
{
593
    PaletteImpl *This = impl_from_IWICPalette(iface);
594
    UINT i;
595 596 597 598 599 600 601

    TRACE("(%p,%p)\n", iface, pfHasAlpha);

    if (!pfHasAlpha) return E_INVALIDARG;

    *pfHasAlpha = FALSE;

602
    EnterCriticalSection(&This->lock);
603 604 605 606 607 608
    for (i=0; i<This->count; i++)
        if ((This->colors[i]&0xff000000) != 0xff000000)
        {
            *pfHasAlpha = TRUE;
            break;
        }
609
    LeaveCriticalSection(&This->lock);
610 611

    return S_OK;
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
}

static const IWICPaletteVtbl PaletteImpl_Vtbl = {
    PaletteImpl_QueryInterface,
    PaletteImpl_AddRef,
    PaletteImpl_Release,
    PaletteImpl_InitializePredefined,
    PaletteImpl_InitializeCustom,
    PaletteImpl_InitializeFromBitmap,
    PaletteImpl_InitializeFromPalette,
    PaletteImpl_GetType,
    PaletteImpl_GetColorCount,
    PaletteImpl_GetColors,
    PaletteImpl_IsBlackWhite,
    PaletteImpl_IsGrayscale,
    PaletteImpl_HasAlpha
};

HRESULT PaletteImpl_Create(IWICPalette **palette)
{
    PaletteImpl *This;

    This = HeapAlloc(GetProcessHeap(), 0, sizeof(PaletteImpl));
    if (!This) return E_OUTOFMEMORY;

637
    This->IWICPalette_iface.lpVtbl = &PaletteImpl_Vtbl;
638
    This->ref = 1;
639 640 641
    This->count = 0;
    This->colors = NULL;
    This->type = WICBitmapPaletteTypeCustom;
642 643
    InitializeCriticalSection(&This->lock);
    This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PaletteImpl.lock");
644

645
    *palette = &This->IWICPalette_iface;
646 647 648

    return S_OK;
}