X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dali%2Finternal%2Fevent%2Fimages%2Fnine-patch-image-impl.cpp;h=ca962369d628aa9bcc31ffbb3f9830e2982119d7;hb=65bb67c665fe465e388e8510eeb5fadda45cf202;hp=c2eb89a5de93820028aad4d7d27633f7788e3437;hpb=760fb67e3ff4b303e1e37657bafe0079e86e1ad8;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 c2eb89a..ca96236 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. @@ -24,14 +24,10 @@ // INTERNAL INCLUDES #include #include -#include #include -#include #include -#include #include #include -#include namespace @@ -104,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: @@ -116,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; + } } } @@ -133,35 +167,38 @@ namespace Dali namespace Internal { -namespace -{ -TypeRegistration mType( typeid( Dali::NinePatchImage ), typeid( Dali::Image ), NULL ); -} // unnamed namespace - -NinePatchImagePtr NinePatchImage::New( const std::string& filename, const ImageAttributes& attributes, ReleasePolicy releasePol ) +NinePatchImagePtr NinePatchImage::New( const std::string& filename ) { - Internal::NinePatchImagePtr internal( new NinePatchImage( filename, attributes, releasePol ) ); + Internal::NinePatchImagePtr internal( new NinePatchImage( filename ) ); internal->Initialize(); return internal; } -NinePatchImage::NinePatchImage( const std::string& filename, const ImageAttributes& attributes, ReleasePolicy releasePol ) -: ResourceImage( IMAGE_LOAD_POLICY_DEFAULT, releasePol ), +NinePatchImage::NinePatchImage( const std::string& filename ) +: ResourceImage(), mParsedBorder(false) { + mUrl = filename; ThreadLocalStorage& tls = ThreadLocalStorage::Get(); - mResourceClient = &tls.GetResourceClient(); Integration::PlatformAbstraction& platformAbstraction = tls.GetPlatformAbstraction(); - Integration::BitmapResourceType resourceType( ImageDimensions::FromFloatVec2( attributes.GetSize() ), attributes.GetScalingMode(), attributes.GetFilterMode(), attributes.GetOrientationCorrection() ); + Integration::BitmapResourceType resourceType; // Note, bitmap is only destroyed when the image is destroyed. - Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously( resourceType, filename ); + 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 { @@ -180,13 +217,22 @@ NinePatchImage::~NinePatchImage() { } -Vector4 NinePatchImage::GetStretchBorders() +const NinePatchImage::StretchRanges& NinePatchImage::GetStretchPixelsX() +{ + if( ! mParsedBorder ) + { + ParseBorders(); + } + return mStretchPixelsX; +} + +const NinePatchImage::StretchRanges& NinePatchImage::GetStretchPixelsY() { if( ! mParsedBorder ) { ParseBorders(); } - return mStretchBorders; + return mStretchPixelsY; } Rect NinePatchImage::GetChildRectangle() @@ -210,7 +256,7 @@ Internal::BufferImagePtr NinePatchImage::CreateCroppedBufferImage() { Pixel::Format pixelFormat = mBitmap->GetPixelFormat(); - cropped = BufferImage::New( mWidth-2, mHeight-2, pixelFormat, Dali::Image::NEVER ); + cropped = BufferImage::New( mWidth-2, mHeight-2, pixelFormat ); Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile(); DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap"); @@ -218,13 +264,13 @@ Internal::BufferImagePtr NinePatchImage::CreateCroppedBufferImage() if( srcProfile ) { PixelBuffer* destPixels = cropped->GetBuffer(); - unsigned int destStride = cropped->GetBufferStride(); - unsigned int pixelWidth = GetBytesPerPixel(pixelFormat); + uint32_t destStride = cropped->GetBufferStride(); + uint32_t pixelWidth = GetBytesPerPixel(pixelFormat); PixelBuffer* srcPixels = mBitmap->GetBuffer(); - unsigned int srcStride = srcProfile->GetBufferStride(); + uint32_t srcStride = srcProfile->GetBufferStride(); - for( unsigned int row=1; row < mHeight-1; ++row ) + for( uint32_t row=1; row < mHeight-1; ++row ) { PixelBuffer* src = srcPixels + row*srcStride + pixelWidth; PixelBuffer* dest = destPixels + (row-1)*destStride; @@ -238,166 +284,198 @@ Internal::BufferImagePtr NinePatchImage::CreateCroppedBufferImage() return cropped; } -void NinePatchImage::Connect() -{ - if( !mTicket ) - { - if( mBitmap ) - { - const ImageTicketPtr& t = mResourceClient->AddBitmapImage(mBitmap.Get()); - mTicket = t.Get(); - mTicket->AddObserver(*this); - } - } - - ++mConnectionCount; -} - -void NinePatchImage::Disconnect() +const std::string& NinePatchImage::GetUrl() const { - if( mConnectionCount > 0 ) - { - --mConnectionCount; - } + return mUrl; } - void NinePatchImage::ParseBorders() { - if( ! mBitmap ) + if( !mBitmap ) { DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n"); return; } + mStretchPixelsX.Clear(); + mStretchPixelsY.Clear(); + 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 ) - { - if(startX1 < 0) - { - startX1 = col; - } - } - else if(startX1 >= 0 && endX1 < 0) + Uint16Pair range = ParseRange( index, width - 2, top, pixelWidth, testByte, testBits, testValue ); + if( range.GetX() != 0xFFFF ) { - endX1 = col; + mStretchPixelsX.PushBack( range ); } + } - if( (bottom[testByte] & testBits) == testValue ) - { - if(startX2 < 0) - { - startX2 = col; - } - } - else if(startX2 >= 0 && endX2 < 0) + //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 ) { - endX2 = col; + mStretchPixelsY.PushBack( range ); } + } - if ( ( endX2 > 0 ) && ( endX1 > 0 ) ) - { + //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; - } + } + } - top+=pixelWidth; - bottom+=pixelWidth; + uint32_t end = width; + for( ; index < width; ++index, pixel += pixelStride ) + { + if( ( pixel[ testByte ] & testBits ) != testValue ) + { + end = index; + ++index; + pixel += pixelStride; + break; } + } - // 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 == '.') { - startY1 = row; + state = HASH; + } + else if(!isalnum(*iter)) + { + state = DONE; } } - else if(startY1 >= 0 && endY1 < 0) - { - endY1 = row; - } - - if((right[testByte] & testBits) == testValue) + break; + case HASH: { - if(startY2 < 0) + if( *iter == '#' || *iter == '9' ) + { + state = HASH_DOT; + } + else { - startY2 = row; + state = DONE; } } - else if(startY2 >= 0 && endY2 < 0) + break; + case HASH_DOT: { - endY2 = row; + if(*iter == '.') + { + match = true; + } + state = DONE; // Stop testing characters } - left += srcStride; - right += srcStride; - - if ( ( endY2 > 0 ) && ( endY1 > 0 ) ) + break; + case DONE: { - break; } + break; } - mStretchBorders.x = startX1; - mStretchBorders.y = startY1; - mStretchBorders.z = mWidth-endX1; - mStretchBorders.w = mHeight-endY1; - - mChildRectangle.x = startX2; - mChildRectangle.y = startY2; - mChildRectangle.width = endX2-startX2; - mChildRectangle.height = endY2-startY2; + // Satisfy prevent + if( state == DONE ) + { + break; + } - mParsedBorder = true; + ++iter; } + return match; } } // namespace Internal