2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://floralicense.org/license/
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an AS IS BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 #include <dali/internal/event/images/nine-patch-image-impl.h>
21 #include <dali/integration-api/bitmap.h>
22 #include <dali/internal/event/images/bitmap-external.h>
23 #include <dali/internal/event/common/thread-local-storage.h>
24 #include <dali/internal/event/resources/resource-client.h>
25 #include <dali/internal/update/manager/update-manager.h>
26 #include <dali/internal/event/images/image-factory.h>
27 #include <dali/integration-api/platform-abstraction.h>
28 #include <dali/integration-api/resource-types.h>
29 #include <dali/integration-api/resource-cache.h>
34 void GetRedOffsetAndMask(Dali::Pixel::Format pixelFormat, int& byteOffset, int& bitMask)
40 case Dali::Pixel::LA88:
47 case Dali::Pixel::RGB888:
48 case Dali::Pixel::RGB8888:
49 case Dali::Pixel::RGBA8888:
55 case Dali::Pixel::BGR8888:
56 case Dali::Pixel::BGRA8888:
62 case Dali::Pixel::RGB565:
68 case Dali::Pixel::BGR565:
75 case Dali::Pixel::RGBA4444:
81 case Dali::Pixel::BGRA4444:
88 case Dali::Pixel::RGBA5551:
95 case Dali::Pixel::BGRA5551:
102 case Dali::Pixel::COMPRESSED_R11_EAC:
103 case Dali::Pixel::COMPRESSED_SIGNED_R11_EAC:
104 case Dali::Pixel::COMPRESSED_RG11_EAC:
105 case Dali::Pixel::COMPRESSED_SIGNED_RG11_EAC:
106 case Dali::Pixel::COMPRESSED_RGB8_ETC2:
107 case Dali::Pixel::COMPRESSED_SRGB8_ETC2:
108 case Dali::Pixel::COMPRESSED_RGB8_ETC1:
109 case Dali::Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
110 case Dali::Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
111 case Dali::Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
112 case Dali::Pixel::COMPRESSED_RGBA8_ETC2_EAC:
113 case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
115 DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple masking-out of per-pixel alpha.\n");
123 } // anonymous namespace
132 NinePatchImagePtr NinePatchImage::New( const std::string& filename, const Dali::ImageAttributes& attributes, LoadPolicy loadPol, ReleasePolicy releasePol )
134 Internal::NinePatchImagePtr internal( new NinePatchImage( filename, attributes, loadPol, releasePol ) );
135 internal->Initialize();
139 NinePatchImage::NinePatchImage( const std::string& filename, const Dali::ImageAttributes& attributes, LoadPolicy loadPol, ReleasePolicy releasePol)
140 : Image(Dali::Image::Immediate, Dali::Image::Never),
145 Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction();
148 platformAbstraction.GetClosestImageSize( filename, attributes, closestSize );
149 ImageAttributes loadedAttrs;
150 loadedAttrs.SetSize( closestSize );
151 mWidth = closestSize.width;
152 mHeight = closestSize.height;
153 Integration::BitmapResourceType resourceType( loadedAttrs );
155 // Note, bitmap is only destroyed when the image is destroyed.
156 Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously(resourceType, filename);
157 mBitmap = static_cast<Integration::Bitmap*>( resource.Get());
160 NinePatchImage* NinePatchImage::GetNinePatchImage( Image* image)
162 return dynamic_cast<NinePatchImage*>(image);
165 NinePatchImage::~NinePatchImage()
169 Vector4 NinePatchImage::GetStretchBorders()
171 if( ! mParsedBorder )
175 return mStretchBorders;
178 Rect<int> NinePatchImage::GetChildRectangle()
180 if( ! mParsedBorder )
184 return mChildRectangle;
187 Internal::BitmapImagePtr NinePatchImage::CreateCroppedBitmapImage()
189 Pixel::Format pixelFormat = mBitmap->GetPixelFormat();
191 BitmapImagePtr cropped = BitmapImage::New( mWidth-2, mHeight-2, pixelFormat,
192 Dali::Image::Immediate, Dali::Image::Never );
194 Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile();
195 DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap");
199 PixelBuffer* destPixels = cropped->GetBuffer();
200 unsigned int destStride = cropped->GetBufferStride();
201 unsigned int pixelWidth = GetBytesPerPixel(pixelFormat);
203 PixelBuffer* srcPixels = mBitmap->GetBuffer();
204 unsigned int srcStride = srcProfile->GetBufferStride();
206 for( unsigned int row=1; row < mHeight-1; ++row )
208 PixelBuffer* src = srcPixels + row*srcStride + pixelWidth;
209 PixelBuffer* dest = destPixels + (row-1)*destStride;
210 memcpy(dest, src, destStride );
215 cropped->Update(area); // default area has no width or height
219 void NinePatchImage::Initialize()
221 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
222 mResourceClient = &tls.GetResourceClient();
225 void NinePatchImage::Connect()
227 if( mConnectionCount == 0 && !mTicket )
229 const ImageTicketPtr& t = mResourceClient->AddBitmapImage(mBitmap.Get());
231 mTicket->AddObserver(*this);
237 void NinePatchImage::Disconnect()
239 if( mConnectionCount > 0 )
246 void NinePatchImage::ParseBorders()
248 Pixel::Format pixelFormat = mBitmap->GetPixelFormat();
250 Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile();
251 DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap");
255 unsigned int pixelWidth = GetBytesPerPixel(pixelFormat);
256 PixelBuffer* srcPixels = mBitmap->GetBuffer();
257 unsigned int srcStride = srcProfile->GetBufferStride();
261 Pixel::GetAlphaOffsetAndMask(pixelFormat, alphaByte, alphaBits);
264 GetRedOffsetAndMask(pixelFormat, redByte, redBits);
266 int testByte = alphaByte;
267 int testBits = alphaBits;
268 int testValue = alphaBits; // Opaque == stretch
273 testValue = 0; // Black == stretch
285 PixelBuffer* top = srcPixels + pixelWidth;
286 PixelBuffer* bottom = srcPixels + (mHeight-1)*srcStride + pixelWidth;
288 // Read the top and bottom rows:
289 // (Also read the last column to ensure end value gets set)
290 for( unsigned int col=1; col < mWidth; ++col )
292 if( (top[testByte] & testBits) == testValue )
299 else if(startX1 >= 0 && endX1 < 0)
305 if( (bottom[testByte] & testBits) == testValue )
312 else if(startX2 >= 0 && endX2 < 0)
321 // Read the left and right columns:
322 PixelBuffer* left = srcPixels + srcStride;
323 PixelBuffer* right = left + (srcStride - pixelWidth);
325 // (Also read the last row to ensure end value gets set)
326 for( unsigned int row=1; row < mHeight; ++row )
328 if((left[testByte] & testBits) == testValue)
335 else if(startY1 >= 0 && endY1 < 0)
341 if((right[testByte] & testBits) == testValue)
348 else if(startY2 >= 0 && endY2 < 0)
357 mStretchBorders.x = startX1-1;
358 mStretchBorders.y = startY1-1;
359 mStretchBorders.z = mWidth-endX1-1;
360 mStretchBorders.w = mHeight-endY1-1;
362 mChildRectangle.x = startX2-1;
363 mChildRectangle.y = startY2-1;
364 mChildRectangle.width = endX2-startX2;
365 mChildRectangle.height = endY2-startY2;
367 mParsedBorder = true;
371 } // namespace Internal