Changeset 58078 in webkit


Ignore:
Timestamp:
Apr 22, 2010 2:38:29 AM (14 years ago)
Author:
eric@webkit.org
Message:

2010-04-22 Stephan Aßmus <superstippi@gmx.de>

Reviewed by David Levin.

[Haiku] Implement ImageBuffer support
https://bugs.webkit.org/show_bug.cgi?id=35288

Covered by existing tests.

Complete implementation of ImageBuffer for Haiku. Uses StillImage
class to export a WebCore::Image and associated GraphicsContext
to perform arbitrary drawing in the offscreen BBitmap buffer.

  • platform/graphics/haiku/ImageBufferData.h:
  • platform/graphics/haiku/ImageBufferHaiku.cpp, (WebCore::ImageBufferData::ImageBufferData), (WebCore::ImageBufferData::~ImageBufferData), (WebCore::ImageBuffer::ImageBuffer), (WebCore::ImageBuffer::~ImageBuffer), (WebCore::ImageBuffer::context), (WebCore::ImageBuffer::image):

Implementation uses offscreen BBitmap and BView, wraps StillImage
around those to provide WebCore::Image interface.

(WebCore::ImageBuffer::platformTransformColorSpace):
(WebCore::convertFromData):

Method just performs BGRA <-> RGBA conversion.

(WebCore::convertFromInternalData):

Method just performs BGRA <-> RGBA conversion and handles
pre-multiplying the color values if requested.

(WebCore::convertToInternalData):

Method just performs BGRA <-> RGBA conversion and handles
de.multiplying the color values if requested.

(WebCore::getImageData):

Common code for the next two methods.

(WebCore::ImageBuffer::getUnmultipliedImageData),
(WebCore::ImageBuffer::getPremultipliedImageData):

Implemented.

(WebCore::putImageData):

Common code for the next two methods.

(WebCore::ImageBuffer::putUnmultipliedImageData),
(WebCore::ImageBuffer::putPremultipliedImageData):

Implemented.

(WebCore::ImageBuffer::toDataURL):

Uses Haiku "Translation Kit" to convert image data to data
of the requested mime type.

Location:
trunk/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r58072 r58078  
     12010-04-22  Stephan Aßmus  <superstippi@gmx.de>
     2
     3        Reviewed by David Levin.
     4
     5        [Haiku] Implement ImageBuffer support
     6        https://bugs.webkit.org/show_bug.cgi?id=35288
     7
     8        Covered by existing tests.
     9
     10        Complete implementation of ImageBuffer for Haiku. Uses StillImage
     11        class to export a WebCore::Image and associated GraphicsContext
     12        to perform arbitrary drawing in the offscreen BBitmap buffer.
     13
     14        * platform/graphics/haiku/ImageBufferData.h:
     15        * platform/graphics/haiku/ImageBufferHaiku.cpp,
     16        (WebCore::ImageBufferData::ImageBufferData),
     17        (WebCore::ImageBufferData::~ImageBufferData),
     18        (WebCore::ImageBuffer::ImageBuffer),
     19        (WebCore::ImageBuffer::~ImageBuffer),
     20        (WebCore::ImageBuffer::context),
     21        (WebCore::ImageBuffer::image):
     22            Implementation uses offscreen BBitmap and BView, wraps StillImage
     23            around those to provide WebCore::Image interface.
     24        (WebCore::ImageBuffer::platformTransformColorSpace):
     25        (WebCore::convertFromData):
     26            Method just performs BGRA <-> RGBA conversion.
     27        (WebCore::convertFromInternalData):
     28            Method just performs BGRA <-> RGBA conversion and handles
     29            pre-multiplying the color values if requested.
     30        (WebCore::convertToInternalData):
     31            Method just performs BGRA <-> RGBA conversion and handles
     32            de.multiplying the color values if requested.
     33        (WebCore::getImageData):
     34            Common code for the next two methods.
     35        (WebCore::ImageBuffer::getUnmultipliedImageData),
     36        (WebCore::ImageBuffer::getPremultipliedImageData):
     37            Implemented.
     38        (WebCore::putImageData):
     39            Common code for the next two methods.
     40        (WebCore::ImageBuffer::putUnmultipliedImageData),
     41        (WebCore::ImageBuffer::putPremultipliedImageData):
     42            Implemented.
     43        (WebCore::ImageBuffer::toDataURL):
     44            Uses Haiku "Translation Kit" to convert image data to data
     45            of the requested mime type.
     46
    1472010-04-22  Adam Barth  <abarth@webkit.org>
    248
  • trunk/WebCore/platform/graphics/haiku/ImageBufferData.h

    r47463 r58078  
    11/*
    2  * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com>
     2 * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
    33 *
    44 * All rights reserved.
     
    2929#define ImageBufferData_h
    3030
     31#include <Bitmap.h>
     32#include <View.h>
     33
    3134namespace WebCore {
    3235
    33     class IntSize;
     36class IntSize;
    3437
    35     class ImageBufferData {
    36     public:
    37         ImageBufferData(const IntSize&);
    38     };
     38class ImageBufferData {
     39public:
     40    ImageBufferData(const IntSize&);
     41    ~ImageBufferData();
    3942
    40 }  // namespace WebCore
     43    BBitmap m_bitmap;
     44    BView m_view;
     45};
    4146
    42 #endif  // ImageBufferData_h
     47} // namespace WebCore
    4348
     49#endif // ImageBufferData_h
     50
  • trunk/WebCore/platform/graphics/haiku/ImageBufferHaiku.cpp

    r47463 r58078  
    11/*
    2  * Copyright (C) 2009 Maxime Simon <simon.maxime@gmail.com>
     2 * Copyright (C) 2010 Stephan Aßmus <superstippi@gmx.de>
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2121 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    2222 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2424 */
    2525
     
    2727#include "ImageBuffer.h"
    2828
     29#include "Base64.h"
    2930#include "GraphicsContext.h"
    3031#include "ImageData.h"
    31 #include "NotImplemented.h"
    32 
     32#include "MIMETypeRegistry.h"
     33#include "StillImageHaiku.h"
     34#include <wtf/text/CString.h>
     35#include <BitmapStream.h>
     36#include <String.h>
     37#include <TranslatorRoster.h>
    3338
    3439namespace WebCore {
    3540
    36 ImageBufferData::ImageBufferData(const IntSize&)
    37 {
    38 }
    39 
    40 ImageBuffer::ImageBuffer(const IntSize&, ImageColorSpace imageColorSpace, bool& success)
    41     : m_data(IntSize())
    42 {
    43     notImplemented();
    44     success = false;
     41ImageBufferData::ImageBufferData(const IntSize& size)
     42    : m_bitmap(BRect(0, 0, size.width() - 1, size.height() - 1), B_RGBA32, true)
     43    , m_view(m_bitmap.Bounds(), "WebKit ImageBufferData", 0, 0)
     44{
     45    // Always keep the bitmap locked, we are the only client.
     46    m_bitmap.Lock();
     47    m_bitmap.AddChild(&m_view);
     48
     49    // Fill with completely transparent color.
     50    memset(m_bitmap.Bits(), 0, m_bitmap.BitsLength());
     51
     52    // Since ImageBuffer is used mainly for Canvas, explicitly initialize
     53    // its view's graphics state with the corresponding canvas defaults
     54    // NOTE: keep in sync with CanvasRenderingContext2D::State
     55    m_view.SetLineMode(B_BUTT_CAP, B_MITER_JOIN, 10);
     56    m_view.SetDrawingMode(B_OP_ALPHA);
     57    m_view.SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_COMPOSITE);
     58}
     59
     60ImageBufferData::~ImageBufferData()
     61{
     62    // Remove the view from the bitmap, keeping it from being free'd twice.
     63    m_view.RemoveSelf();
     64    m_bitmap.Unlock();
     65}
     66
     67ImageBuffer::ImageBuffer(const IntSize& size, ImageColorSpace imageColorSpace, bool& success)
     68    : m_data(size)
     69    , m_size(size)
     70{
     71    m_context.set(new GraphicsContext(&m_data.m_view));
     72    success = true;
    4573}
    4674
     
    5179GraphicsContext* ImageBuffer::context() const
    5280{
    53     notImplemented();
    54     return 0;
    55 }
     81    ASSERT(m_data.m_view.Window());
     82
     83    return m_context.get();
     84}
     85
     86Image* ImageBuffer::image() const
     87{
     88    if (!m_image) {
     89        // It's assumed that if image() is called, the actual rendering to the
     90        // GraphicsContext must be done.
     91        ASSERT(context());
     92        m_data.m_view.Sync();
     93        m_image = StillImage::create(m_data.m_bitmap);
     94    }
     95
     96    return m_image.get();
     97}
     98
     99void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
     100{
     101    uint8* rowData = reinterpret_cast<uint8*>(m_data.m_bitmap.Bits());
     102    unsigned bytesPerRow = m_data.m_bitmap.BytesPerRow();
     103    unsigned rows = m_size.height();
     104    unsigned columns = m_size.width();
     105    for (unsigned y = 0; y < rows; y++) {
     106        uint8* pixel = rowData;
     107        for (unsigned x = 0; x < columns; x++) {
     108            // lookUpTable doesn't seem to support a LUT for each color channel
     109            // separately (judging from the other ports). We don't need to
     110            // convert from/to pre-multiplied color space since BBitmap storage
     111            // is not pre-multiplied.
     112            pixel[0] = lookUpTable[pixel[0]];
     113            pixel[1] = lookUpTable[pixel[1]];
     114            pixel[2] = lookUpTable[pixel[2]];
     115            // alpha stays unmodified.
     116            pixel += 4;
     117        }
     118        rowData += bytesPerRow;
     119    }
     120}
     121
     122static inline void convertFromData(const uint8* sourceRows, unsigned sourceBytesPerRow,
     123                                   uint8* destRows, unsigned destBytesPerRow,
     124                                   unsigned rows, unsigned columns)
     125{
     126    for (unsigned y = 0; y < rows; y++) {
     127        const uint8* sourcePixel = sourceRows;
     128        uint8* destPixel = destRows;
     129        for (unsigned x = 0; x < columns; x++) {
     130            // RGBA -> BGRA or BGRA -> RGBA
     131            destPixel[0] = sourcePixel[2];
     132            destPixel[1] = sourcePixel[1];
     133            destPixel[2] = sourcePixel[0];
     134            destPixel[3] = sourcePixel[3];
     135            destPixel += 4;
     136            sourcePixel += 4;
     137        }
     138        sourceRows += sourceBytesPerRow;
     139        destRows += destBytesPerRow;
     140    }
     141}
     142
     143static inline void convertFromInternalData(const uint8* sourceRows, unsigned sourceBytesPerRow,
     144                                           uint8* destRows, unsigned destBytesPerRow,
     145                                           unsigned rows, unsigned columns,
     146                                           bool premultiplied)
     147{
     148    if (premultiplied) {
     149        // Internal storage is not pre-multiplied, pre-multiply on the fly.
     150        for (unsigned y = 0; y < rows; y++) {
     151            const uint8* sourcePixel = sourceRows;
     152            uint8* destPixel = destRows;
     153            for (unsigned x = 0; x < columns; x++) {
     154                // RGBA -> BGRA or BGRA -> RGBA
     155                destPixel[0] = static_cast<uint16>(sourcePixel[2]) * sourcePixel[3] / 255;
     156                destPixel[1] = static_cast<uint16>(sourcePixel[1]) * sourcePixel[3] / 255;
     157                destPixel[2] = static_cast<uint16>(sourcePixel[0]) * sourcePixel[3] / 255;
     158                destPixel[3] = sourcePixel[3];
     159                destPixel += 4;
     160                sourcePixel += 4;
     161            }
     162            sourceRows += sourceBytesPerRow;
     163            destRows += destBytesPerRow;
     164        }
     165    } else {
     166        convertFromData(sourceRows, sourceBytesPerRow,
     167                        destRows, destBytesPerRow,
     168                        rows, columns);
     169    }
     170}
     171
     172static inline void convertToInternalData(const uint8* sourceRows, unsigned sourceBytesPerRow,
     173                                         uint8* destRows, unsigned destBytesPerRow,
     174                                         unsigned rows, unsigned columns,
     175                                         bool premultiplied)
     176{
     177    if (premultiplied) {
     178        // Internal storage is not pre-multiplied, de-multiply source data.
     179        for (unsigned y = 0; y < rows; y++) {
     180            const uint8* sourcePixel = sourceRows;
     181            uint8* destPixel = destRows;
     182            for (unsigned x = 0; x < columns; x++) {
     183                // RGBA -> BGRA or BGRA -> RGBA
     184                if (sourcePixel[3]) {
     185                    destPixel[0] = static_cast<uint16>(sourcePixel[2]) * 255 / sourcePixel[3];
     186                    destPixel[1] = static_cast<uint16>(sourcePixel[1]) * 255 / sourcePixel[3];
     187                    destPixel[2] = static_cast<uint16>(sourcePixel[0]) * 255 / sourcePixel[3];
     188                    destPixel[3] = sourcePixel[3];
     189                } else {
     190                    destPixel[0] = 0;
     191                    destPixel[1] = 0;
     192                    destPixel[2] = 0;
     193                    destPixel[3] = 0;
     194                }
     195                destPixel += 4;
     196                sourcePixel += 4;
     197            }
     198            sourceRows += sourceBytesPerRow;
     199            destRows += destBytesPerRow;
     200        }
     201    } else {
     202        convertFromData(sourceRows, sourceBytesPerRow,
     203                        destRows, destBytesPerRow,
     204                        rows, columns);
     205    }
     206}
     207
     208static PassRefPtr<ImageData> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size, bool premultiplied)
     209{
     210    PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
     211    unsigned char* data = result->data()->data()->data();
     212
     213    // If the destination image is larger than the source image, the outside
     214    // regions need to be transparent. This way is simply, although with a
     215    // a slight overhead for the inside region.
     216    if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > size.width() || (rect.y() + rect.height()) > size.height())
     217        memset(data, 0, result->data()->length());
     218
     219    // If the requested image is outside the source image, we can return at
     220    // this point.
     221    if (rect.x() > size.width() || rect.y() > size.height() || rect.right() < 0 || rect.bottom() < 0)
     222        return result;
     223
     224    // Now we know there must be an intersection rect which we need to extract.
     225    BRect sourceRect(0, 0, size.width() - 1, size.height() - 1);
     226    sourceRect = BRect(rect) & sourceRect;
     227
     228    unsigned destBytesPerRow = 4 * rect.width();
     229    unsigned char* destRows = data;
     230    // Offset the destination pointer to point at the first pixel of the
     231    // intersection rect.
     232    destRows += (rect.x() - static_cast<int>(sourceRect.left)) * 4
     233        + (rect.y() - static_cast<int>(sourceRect.top)) * destBytesPerRow;
     234
     235    const uint8* sourceRows = reinterpret_cast<const uint8*>(imageData.m_bitmap.Bits());
     236    uint32 sourceBytesPerRow = imageData.m_bitmap.BytesPerRow();
     237    // Offset the source pointer to point at the first pixel of the
     238    // intersection rect.
     239    sourceRows += static_cast<int>(sourceRect.left) * 4
     240        + static_cast<int>(sourceRect.top) * sourceBytesPerRow;
     241
     242    unsigned rows = sourceRect.IntegerHeight() + 1;
     243    unsigned columns = sourceRect.IntegerWidth() + 1;
     244    convertFromInternalData(sourceRows, sourceBytesPerRow, destRows, destBytesPerRow,
     245        rows, columns, premultiplied);
     246
     247    return result;
     248}
     249
    56250
    57251PassRefPtr<ImageData> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
    58252{
    59     notImplemented();
    60     return 0;
     253    // Make sure all asynchronous drawing has finished
     254    m_data.m_view.Sync();
     255    return getImageData(rect, m_data, m_size, false);
    61256}
    62257
    63258PassRefPtr<ImageData> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
    64259{
    65     notImplemented();
    66     return 0;
     260    // Make sure all asynchronous drawing has finished
     261    m_data.m_view.Sync();
     262    return getImageData(rect, m_data, m_size, true);
     263}
     264
     265static void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& imageData, const IntSize& size, bool premultiplied)
     266{
     267    // If the source image is outside the destination image, we can return at
     268    // this point.
     269    // FIXME: Check if this isn't already done in WebCore.
     270    if (destPoint.x() > size.width() || destPoint.y() > size.height()
     271        || destPoint.x() + sourceRect.width() < 0
     272        || destPoint.y() + sourceRect.height() < 0) {
     273        return;
     274    }
     275
     276    const unsigned char* sourceRows = source->data()->data()->data();
     277    unsigned sourceBytesPerRow = 4 * source->width();
     278    // Offset the source pointer to the first pixel of the source rect.
     279    sourceRows += sourceRect.x() * 4 + sourceRect.y() * sourceBytesPerRow;
     280
     281    // We know there must be an intersection rect.
     282    BRect destRect(destPoint.x(), destPoint.y(), sourceRect.width() - 1, sourceRect.height() - 1);
     283    destRect = destRect & BRect(0, 0, size.width() - 1, size.height() - 1);
     284
     285    unsigned char* destRows = reinterpret_cast<unsigned char*>(imageData.m_bitmap.Bits());
     286    uint32 destBytesPerRow = imageData.m_bitmap.BytesPerRow();
     287    // Offset the source pointer to point at the first pixel of the
     288    // intersection rect.
     289    destRows += static_cast<int>(destRect.left) * 4
     290        + static_cast<int>(destRect.top) * destBytesPerRow;
     291
     292    unsigned rows = sourceRect.height();
     293    unsigned columns = sourceRect.width();
     294    convertToInternalData(sourceRows, sourceBytesPerRow, destRows, destBytesPerRow,
     295        rows, columns, premultiplied);
    67296}
    68297
    69298void ImageBuffer::putUnmultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
    70299{
    71     notImplemented();
     300    // Make sure all asynchronous drawing has finished
     301    m_data.m_view.Sync();
     302    putImageData(source, sourceRect, destPoint, m_data, m_size, false);
    72303}
    73304
    74305void ImageBuffer::putPremultipliedImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
    75306{
    76     notImplemented();
    77 }
    78 
    79 String ImageBuffer::toDataURL(const String&) const
    80 {
    81     notImplemented();
    82     return String();
    83 }
    84 
    85 Image* ImageBuffer::image() const
    86 {
    87     notImplemented();
    88     return 0;
    89 }
    90 
    91 void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
    92 {
    93     notImplemented();
     307    // Make sure all asynchronous drawing has finished
     308    m_data.m_view.Sync();
     309    putImageData(source, sourceRect, destPoint, m_data, m_size, true);
     310}
     311
     312String ImageBuffer::toDataURL(const String& mimeType) const
     313{
     314    if (!MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType))
     315        return "data:,";
     316
     317    BString mimeTypeString(mimeType);
     318
     319    uint32 translatorType = 0;
     320
     321    BTranslatorRoster* roster = BTranslatorRoster::Default();
     322    translator_id* translators;
     323    int32 translatorCount;
     324    roster->GetAllTranslators(&translators, &translatorCount);
     325    for (int32 i = 0; i < translatorCount; i++) {
     326        // Skip translators that don't support archived BBitmaps as input data.
     327        const translation_format* inputFormats;
     328        int32 formatCount;
     329        roster->GetInputFormats(translators[i], &inputFormats, &formatCount);
     330        bool supportsBitmaps = false;
     331        for (int32 j = 0; j < formatCount; j++) {
     332            if (inputFormats[j].type == B_TRANSLATOR_BITMAP) {
     333                supportsBitmaps = true;
     334                break;
     335            }
     336        }
     337        if (!supportsBitmaps)
     338            continue;
     339
     340        const translation_format* outputFormats;
     341        roster->GetOutputFormats(translators[i], &outputFormats, &formatCount);
     342        for (int32 j = 0; j < formatCount; j++) {
     343            if (outputFormats[j].group == B_TRANSLATOR_BITMAP
     344                && mimeTypeString == outputFormats[j].MIME) {
     345                translatorType = outputFormats[j].type;
     346            }
     347        }
     348        if (translatorType)
     349            break;
     350    }
     351
     352
     353    BMallocIO translatedStream;
     354    BBitmap* bitmap = const_cast<BBitmap*>(&m_data.m_bitmap);
     355        // BBitmapStream doesn't take "const Bitmap*"...
     356    BBitmapStream bitmapStream(bitmap);
     357    if (roster->Translate(&bitmapStream, 0, 0, &translatedStream, translatorType,
     358                          B_TRANSLATOR_BITMAP, mimeType.utf8().data()) != B_OK) {
     359        bitmapStream.DetachBitmap(&bitmap);
     360        return "data:,";
     361    }
     362
     363    bitmapStream.DetachBitmap(&bitmap);
     364
     365    Vector<char> encodedBuffer;
     366    base64Encode(reinterpret_cast<const char*>(translatedStream.Buffer()),
     367                 translatedStream.BufferLength(), encodedBuffer);
     368
     369    return String::format("data:%s;base64,%s", mimeType.utf8().data(),
     370                          encodedBuffer.data());
    94371}
    95372
Note: See TracChangeset for help on using the changeset viewer.