X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fevent%2Fimages%2Fnine-patch-image-impl.cpp;h=7662edc19cd1ed95618c24f769d75e2e1d6ffb00;hb=8d71875559bace2efc28776da87812c618f0b26d;hp=3c8a06950f4e5eb31165c75d01273b214d94ca0f;hpb=27619bbc4c1d443e89a6cdd116e544f6d9657fa4;p=platform%2Fcore%2Fuifw%2Fdali-core.git diff --git a/dali/internal/event/images/nine-patch-image-impl.cpp b/dali/internal/event/images/nine-patch-image-impl.cpp index 3c8a069..7662edc 100644 --- a/dali/internal/event/images/nine-patch-image-impl.cpp +++ b/dali/internal/event/images/nine-patch-image-impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * Copyright (c) 2018 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,17 +18,16 @@ // CLASS HEADER #include +// EXTERNAL INCLUDES +#include // for memcmp + // INTERNAL INCLUDES #include #include -#include #include -#include #include -#include #include #include -#include namespace @@ -101,6 +100,7 @@ void GetRedOffsetAndMask(Dali::Pixel::Format pixelFormat, int& byteOffset, int& break; } + case Dali::Pixel::INVALID: case Dali::Pixel::COMPRESSED_R11_EAC: case Dali::Pixel::COMPRESSED_SIGNED_R11_EAC: case Dali::Pixel::COMPRESSED_RG11_EAC: @@ -113,12 +113,49 @@ void GetRedOffsetAndMask(Dali::Pixel::Format pixelFormat, int& byteOffset, int& case Dali::Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: case Dali::Pixel::COMPRESSED_RGBA8_ETC2_EAC: case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_4x4_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_5x4_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_5x5_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_6x5_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_6x6_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x5_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x6_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_8x8_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x5_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x6_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x8_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_10x10_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_12x10_KHR: + case Dali::Pixel::COMPRESSED_RGBA_ASTC_12x12_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: + case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: { DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple masking-out of per-pixel alpha.\n"); byteOffset=0; bitMask=0; break; } + + case Dali::Pixel::RGB16F: + case Dali::Pixel::RGB32F: + { + DALI_LOG_ERROR("Pixel format not compatible.\n"); + byteOffset=0; + bitMask=0; + break; + } } } @@ -135,36 +172,48 @@ namespace TypeRegistration mType( typeid( Dali::NinePatchImage ), typeid( Dali::Image ), NULL ); } // unnamed namespace -NinePatchImagePtr NinePatchImage::New( const std::string& filename, const Dali::ImageAttributes& attributes, LoadPolicy loadPol, ReleasePolicy releasePol ) +NinePatchImagePtr NinePatchImage::New( const std::string& filename ) { - Internal::NinePatchImagePtr internal( new NinePatchImage( filename, attributes, loadPol, releasePol ) ); + Internal::NinePatchImagePtr internal( new NinePatchImage( filename ) ); internal->Initialize(); return internal; } -NinePatchImage::NinePatchImage( const std::string& filename, const Dali::ImageAttributes& attributes, LoadPolicy loadPol, ReleasePolicy releasePol) -: Image(Dali::Image::Immediate, Dali::Image::Never), +NinePatchImage::NinePatchImage( const std::string& filename ) +: ResourceImage(), mParsedBorder(false) { + mUrl = filename; ThreadLocalStorage& tls = ThreadLocalStorage::Get(); - mResourceClient = &tls.GetResourceClient(); - Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction(); - - Vector2 closestSize; - platformAbstraction.GetClosestImageSize( filename, attributes, closestSize ); - ImageAttributes loadedAttrs; - loadedAttrs.SetSize( closestSize ); - mWidth = closestSize.width; - mHeight = closestSize.height; - Integration::BitmapResourceType resourceType( loadedAttrs ); + Integration::PlatformAbstraction& platformAbstraction = tls.GetPlatformAbstraction(); + Integration::BitmapResourceType resourceType; // Note, bitmap is only destroyed when the image is destroyed. - Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously(resourceType, filename); - mBitmap = static_cast( resource.Get()); + Integration::ResourcePointer resource = platformAbstraction.LoadImageSynchronously( resourceType, filename ); + if( resource ) + { + mBitmap = static_cast( resource.Get()); + + mWidth = mBitmap->GetImageWidth(); + mHeight = mBitmap->GetImageHeight(); + mTexture = Texture::New( Dali::TextureType::TEXTURE_2D, mBitmap->GetPixelFormat(), mWidth, mHeight ); + + uint32_t bufferSize = mBitmap->GetBufferSize(); + uint8_t* buffer = new uint8_t[bufferSize]; + memcpy( buffer, mBitmap->GetBuffer(), bufferSize ); + PixelDataPtr pixelData = PixelData::New( buffer, bufferSize, mWidth, mHeight, mBitmap->GetPixelFormat(), Dali::PixelData::DELETE_ARRAY ); + mTexture->Upload( pixelData ); + } + else + { + mBitmap.Reset(); + mWidth = 0; + mHeight = 0; + } } -NinePatchImage* NinePatchImage::GetNinePatchImage( Image* image) +NinePatchImage* NinePatchImage::DownCast( Image* image) { return dynamic_cast(image); } @@ -173,13 +222,22 @@ NinePatchImage::~NinePatchImage() { } -Vector4 NinePatchImage::GetStretchBorders() +const NinePatchImage::StretchRanges& NinePatchImage::GetStretchPixelsX() { if( ! mParsedBorder ) { ParseBorders(); } - return mStretchBorders; + return mStretchPixelsX; +} + +const NinePatchImage::StretchRanges& NinePatchImage::GetStretchPixelsY() +{ + if( ! mParsedBorder ) + { + ParseBorders(); + } + return mStretchPixelsY; } Rect NinePatchImage::GetChildRectangle() @@ -191,182 +249,238 @@ Rect NinePatchImage::GetChildRectangle() return mChildRectangle; } -Internal::BitmapImagePtr NinePatchImage::CreateCroppedBitmapImage() +Internal::BufferImagePtr NinePatchImage::CreateCroppedBufferImage() { - Pixel::Format pixelFormat = mBitmap->GetPixelFormat(); - - BitmapImagePtr cropped = BitmapImage::New( mWidth-2, mHeight-2, pixelFormat, - Dali::Image::Immediate, Dali::Image::Never ); - - Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile(); - DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap"); + BufferImagePtr cropped; - if( srcProfile ) + if( ! mBitmap ) + { + DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n"); + } + else { - PixelBuffer* destPixels = cropped->GetBuffer(); - unsigned int destStride = cropped->GetBufferStride(); - unsigned int pixelWidth = GetBytesPerPixel(pixelFormat); + Pixel::Format pixelFormat = mBitmap->GetPixelFormat(); - PixelBuffer* srcPixels = mBitmap->GetBuffer(); - unsigned int srcStride = srcProfile->GetBufferStride(); + cropped = BufferImage::New( mWidth-2, mHeight-2, pixelFormat ); - for( unsigned int row=1; row < mHeight-1; ++row ) + Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile(); + DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap"); + + if( srcProfile ) { - PixelBuffer* src = srcPixels + row*srcStride + pixelWidth; - PixelBuffer* dest = destPixels + (row-1)*destStride; - memcpy(dest, src, destStride ); + PixelBuffer* destPixels = cropped->GetBuffer(); + uint32_t destStride = cropped->GetBufferStride(); + uint32_t pixelWidth = GetBytesPerPixel(pixelFormat); + + PixelBuffer* srcPixels = mBitmap->GetBuffer(); + uint32_t srcStride = srcProfile->GetBufferStride(); + + for( uint32_t row=1; row < mHeight-1; ++row ) + { + PixelBuffer* src = srcPixels + row*srcStride + pixelWidth; + PixelBuffer* dest = destPixels + (row-1)*destStride; + memcpy(dest, src, destStride ); + } } - } - RectArea area; - cropped->Update(area); // default area has no width or height + RectArea area; + cropped->Update(area); // default area has no width or height + } return cropped; } -void NinePatchImage::Connect() +const std::string& NinePatchImage::GetUrl() const { - if( mConnectionCount == 0 && !mTicket ) - { - const ImageTicketPtr& t = mResourceClient->AddBitmapImage(mBitmap.Get()); - mTicket = t.Get(); - mTicket->AddObserver(*this); - } - - ++mConnectionCount; + return mUrl; } -void NinePatchImage::Disconnect() +void NinePatchImage::ParseBorders() { - if( mConnectionCount > 0 ) + if( !mBitmap ) { - --mConnectionCount; + DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n"); + return; } -} + mStretchPixelsX.Clear(); + mStretchPixelsY.Clear(); -void NinePatchImage::ParseBorders() -{ Pixel::Format pixelFormat = mBitmap->GetPixelFormat(); - Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile(); - DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap"); + const Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile(); + DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap" ); if( srcProfile ) { - unsigned int pixelWidth = GetBytesPerPixel(pixelFormat); - PixelBuffer* srcPixels = mBitmap->GetBuffer(); - unsigned int srcStride = srcProfile->GetBufferStride(); - - int alphaByte=0; - int alphaBits=0; - Pixel::GetAlphaOffsetAndMask(pixelFormat, alphaByte, alphaBits); - int redByte=0; - int redBits=0; - GetRedOffsetAndMask(pixelFormat, redByte, redBits); + int alphaByte = 0; + int alphaBits = 0; + Pixel::GetAlphaOffsetAndMask( pixelFormat, alphaByte, alphaBits ); int testByte = alphaByte; int testBits = alphaBits; int testValue = alphaBits; // Opaque == stretch if( ! alphaBits ) { - testByte = redByte; - testBits = redBits; + GetRedOffsetAndMask( pixelFormat, testByte, testBits ); testValue = 0; // Black == stretch } - int startX1=-1; - int endX1=-1; - int startY1=-1; - int endY1=-1; - int startX2=-1; - int endX2=-1; - int startY2=-1; - int endY2=-1; - - PixelBuffer* top = srcPixels + pixelWidth; - PixelBuffer* bottom = srcPixels + (mHeight-1)*srcStride + pixelWidth; - - // Read the top and bottom rows: - // (Also read the last column to ensure end value gets set) - for( unsigned int col=1; col < mWidth; ++col ) + uint32_t pixelWidth = GetBytesPerPixel( pixelFormat ); + const PixelBuffer* srcPixels = mBitmap->GetBuffer(); + uint32_t srcStride = srcProfile->GetBufferStride(); + + //TOP + const PixelBuffer* top = srcPixels + pixelWidth; + uint32_t index = 0; + uint32_t width = mBitmap->GetImageWidth(); + uint32_t height = mBitmap->GetImageHeight(); + + for(; index < width - 2; ) { - if( (top[testByte] & testBits) == testValue ) + Uint16Pair range = ParseRange( index, width - 2, top, pixelWidth, testByte, testBits, testValue ); + if( range.GetX() != 0xFFFF ) { - if(startX1 < 0) - { - startX1 = col; - } - } - else if(startX1 >= 0 && endX1 < 0) - { - endX1 = col-1; - break; + mStretchPixelsX.PushBack( range ); } + } - if( (bottom[testByte] & testBits) == testValue ) + //LEFT + const PixelBuffer* left = srcPixels + srcStride; + index = 0; + for(; index < height - 2; ) + { + Uint16Pair range = ParseRange( index, height - 2, left, srcStride, testByte, testBits, testValue ); + if( range.GetX() != 0xFFFF ) { - if(startX2 < 0) - { - startX2 = col; - } + mStretchPixelsY.PushBack( range ); } - else if(startX2 >= 0 && endX2 < 0) - { - endX2 = col-1; + } + + //If there are no stretch pixels then make the entire image stretchable + if( mStretchPixelsX.Size() == 0 ) + { + mStretchPixelsX.PushBack( Uint16Pair( 0, width - 2 ) ); + } + if( mStretchPixelsY.Size() == 0 ) + { + mStretchPixelsY.PushBack( Uint16Pair( 0, height - 2 ) ); + } + + //Child Rectangle + //BOTTOM + const PixelBuffer* bottom = srcPixels + ( height - 1 ) * srcStride + pixelWidth; + index = 0; + Uint16Pair contentRangeX = ParseRange( index, width - 2, bottom, pixelWidth, testByte, testBits, testValue ); + if( contentRangeX.GetX() == 0xFFFF ) + { + contentRangeX = Uint16Pair(); + } + + //RIGHT + const PixelBuffer* right = srcPixels + srcStride + ( width - 1 ) * pixelWidth; + index = 0; + Uint16Pair contentRangeY = ParseRange( index, height - 2, right, srcStride, testByte, testBits, testValue ); + if( contentRangeY.GetX() == 0xFFFF ) + { + contentRangeY = Uint16Pair(); + } + + mChildRectangle.x = contentRangeX.GetX() + 1; + mChildRectangle.y = contentRangeY.GetX() + 1; + mChildRectangle.width = contentRangeX.GetY() - contentRangeX.GetX(); + mChildRectangle.height = contentRangeY.GetY() - contentRangeY.GetX(); + + mParsedBorder = true; + } +} + +Uint16Pair NinePatchImage::ParseRange( uint32_t& index, uint32_t width, const PixelBuffer* & pixel, uint32_t pixelStride, int testByte, int testBits, int testValue ) +{ + uint32_t start = 0xFFFF; + for( ; index < width; ++index, pixel += pixelStride ) + { + if( ( pixel[ testByte ] & testBits ) == testValue ) + { + start = index; + ++index; + pixel += pixelStride; + break; + } + } + + uint32_t end = width; + for( ; index < width; ++index, pixel += pixelStride ) + { + if( ( pixel[ testByte ] & testBits ) != testValue ) + { + end = index; + ++index; + pixel += pixelStride; break; - } - top+=pixelWidth; - bottom+=pixelWidth; } + } - // Read the left and right columns: - PixelBuffer* left = srcPixels + srcStride; - PixelBuffer* right = left + (srcStride - pixelWidth); + return Uint16Pair( start, end ); +} + +bool NinePatchImage::IsNinePatchUrl( const std::string& url ) +{ + bool match = false; - // (Also read the last row to ensure end value gets set) - for( unsigned int row=1; row < mHeight; ++row ) + std::string::const_reverse_iterator iter = url.rbegin(); + enum { SUFFIX, HASH, HASH_DOT, DONE } state = SUFFIX; + while(iter < url.rend()) + { + switch(state) { - if((left[testByte] & testBits) == testValue) + case SUFFIX: { - if(startY1 < 0) + if(*iter == '.') + { + state = HASH; + } + else if(!isalnum(*iter)) { - startY1 = row; + state = DONE; } } - else if(startY1 >= 0 && endY1 < 0) + break; + case HASH: { - endY1 = row-1; - break; + if( *iter == '#' || *iter == '9' ) + { + state = HASH_DOT; + } + else + { + state = DONE; + } } - - if((right[testByte] & testBits) == testValue) + break; + case HASH_DOT: { - if(startY2 < 0) + if(*iter == '.') { - startY2 = row; + match = true; } + state = DONE; // Stop testing characters } - else if(startY2 >= 0 && endY2 < 0) + break; + case DONE: { - endY2 = row-1; - break; } - left += srcStride; - right += srcStride; + break; } - mStretchBorders.x = startX1-1; - mStretchBorders.y = startY1-1; - mStretchBorders.z = mWidth-endX1-1; - mStretchBorders.w = mHeight-endY1-1; - - mChildRectangle.x = startX2-1; - mChildRectangle.y = startY2-1; - mChildRectangle.width = endX2-startX2; - mChildRectangle.height = endY2-startY2; + // Satisfy prevent + if( state == DONE ) + { + break; + } - mParsedBorder = true; + ++iter; } + return match; } } // namespace Internal