2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/images/nine-patch-image-impl.h>
22 #include <cstring> // for memcmp
25 #include <dali/public-api/object/type-registry.h>
26 #include <dali/integration-api/bitmap.h>
27 #include <dali/internal/event/images/bitmap-external.h>
28 #include <dali/internal/event/common/thread-local-storage.h>
29 #include <dali/internal/event/resources/resource-client.h>
30 #include <dali/internal/update/manager/update-manager.h>
31 #include <dali/internal/event/images/image-factory.h>
32 #include <dali/integration-api/platform-abstraction.h>
33 #include <dali/integration-api/resource-types.h>
34 #include <dali/integration-api/resource-cache.h>
39 void GetRedOffsetAndMask(Dali::Pixel::Format pixelFormat, int& byteOffset, int& bitMask)
45 case Dali::Pixel::LA88:
52 case Dali::Pixel::RGB888:
53 case Dali::Pixel::RGB8888:
54 case Dali::Pixel::RGBA8888:
60 case Dali::Pixel::BGR8888:
61 case Dali::Pixel::BGRA8888:
67 case Dali::Pixel::RGB565:
73 case Dali::Pixel::BGR565:
80 case Dali::Pixel::RGBA4444:
86 case Dali::Pixel::BGRA4444:
93 case Dali::Pixel::RGBA5551:
100 case Dali::Pixel::BGRA5551:
107 case Dali::Pixel::COMPRESSED_R11_EAC:
108 case Dali::Pixel::COMPRESSED_SIGNED_R11_EAC:
109 case Dali::Pixel::COMPRESSED_RG11_EAC:
110 case Dali::Pixel::COMPRESSED_SIGNED_RG11_EAC:
111 case Dali::Pixel::COMPRESSED_RGB8_ETC2:
112 case Dali::Pixel::COMPRESSED_SRGB8_ETC2:
113 case Dali::Pixel::COMPRESSED_RGB8_ETC1:
114 case Dali::Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
115 case Dali::Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
116 case Dali::Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
117 case Dali::Pixel::COMPRESSED_RGBA8_ETC2_EAC:
118 case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
120 DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple masking-out of per-pixel alpha.\n");
128 } // anonymous namespace
138 TypeRegistration mType( typeid( Dali::NinePatchImage ), typeid( Dali::Image ), NULL );
139 } // unnamed namespace
141 NinePatchImagePtr NinePatchImage::New( const std::string& filename, const ImageAttributes& attributes, ReleasePolicy releasePol )
143 Internal::NinePatchImagePtr internal( new NinePatchImage( filename, attributes, releasePol ) );
144 internal->Initialize();
148 NinePatchImage::NinePatchImage( const std::string& filename, const ImageAttributes& attributes, ReleasePolicy releasePol )
149 : ResourceImage( IMAGE_LOAD_POLICY_DEFAULT, releasePol ),
152 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
153 mResourceClient = &tls.GetResourceClient();
155 Integration::PlatformAbstraction& platformAbstraction = tls.GetPlatformAbstraction();
156 Integration::BitmapResourceType resourceType( ImageDimensions::FromFloatVec2( attributes.GetSize() ), attributes.GetScalingMode(), attributes.GetFilterMode(), attributes.GetOrientationCorrection() );
158 // Note, bitmap is only destroyed when the image is destroyed.
159 Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously( resourceType, filename );
162 mBitmap = static_cast<Integration::Bitmap*>( resource.Get());
163 mWidth = mBitmap->GetImageWidth();
164 mHeight = mBitmap->GetImageHeight();
174 NinePatchImage* NinePatchImage::DownCast( Image* image)
176 return dynamic_cast<NinePatchImage*>(image);
179 NinePatchImage::~NinePatchImage()
183 Vector4 NinePatchImage::GetStretchBorders()
185 if( ! mParsedBorder )
189 return mStretchBorders;
192 Rect<int> NinePatchImage::GetChildRectangle()
194 if( ! mParsedBorder )
198 return mChildRectangle;
201 Internal::BufferImagePtr NinePatchImage::CreateCroppedBufferImage()
203 BufferImagePtr cropped;
207 DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n");
211 Pixel::Format pixelFormat = mBitmap->GetPixelFormat();
213 cropped = BufferImage::New( mWidth-2, mHeight-2, pixelFormat, Dali::Image::NEVER );
215 Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile();
216 DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap");
220 PixelBuffer* destPixels = cropped->GetBuffer();
221 unsigned int destStride = cropped->GetBufferStride();
222 unsigned int pixelWidth = GetBytesPerPixel(pixelFormat);
224 PixelBuffer* srcPixels = mBitmap->GetBuffer();
225 unsigned int srcStride = srcProfile->GetBufferStride();
227 for( unsigned int row=1; row < mHeight-1; ++row )
229 PixelBuffer* src = srcPixels + row*srcStride + pixelWidth;
230 PixelBuffer* dest = destPixels + (row-1)*destStride;
231 memcpy(dest, src, destStride );
236 cropped->Update(area); // default area has no width or height
241 void NinePatchImage::Connect()
247 const ImageTicketPtr& t = mResourceClient->AddBitmapImage(mBitmap.Get());
249 mTicket->AddObserver(*this);
256 void NinePatchImage::Disconnect()
258 if( mConnectionCount > 0 )
265 void NinePatchImage::ParseBorders()
269 DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n");
273 Pixel::Format pixelFormat = mBitmap->GetPixelFormat();
275 Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile();
276 DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap");
280 unsigned int pixelWidth = GetBytesPerPixel(pixelFormat);
281 PixelBuffer* srcPixels = mBitmap->GetBuffer();
282 unsigned int srcStride = srcProfile->GetBufferStride();
286 Pixel::GetAlphaOffsetAndMask(pixelFormat, alphaByte, alphaBits);
289 GetRedOffsetAndMask(pixelFormat, redByte, redBits);
291 int testByte = alphaByte;
292 int testBits = alphaBits;
293 int testValue = alphaBits; // Opaque == stretch
298 testValue = 0; // Black == stretch
310 PixelBuffer* top = srcPixels + pixelWidth;
311 PixelBuffer* bottom = srcPixels + (mHeight-1)*srcStride + pixelWidth;
313 // Read the top and bottom rows:
314 // (Also read the last column to ensure end value gets set)
315 for( unsigned int col=1; col < mWidth; ++col )
317 if( (top[testByte] & testBits) == testValue )
324 else if(startX1 >= 0 && endX1 < 0)
329 if( (bottom[testByte] & testBits) == testValue )
336 else if(startX2 >= 0 && endX2 < 0)
341 if ( ( endX2 > 0 ) && ( endX1 > 0 ) )
350 // Read the left and right columns:
351 PixelBuffer* left = srcPixels + srcStride;
352 PixelBuffer* right = left + (srcStride - pixelWidth);
354 // (Also read the last row to ensure end value gets set)
355 for( unsigned int row=1; row < mHeight; ++row )
357 if((left[testByte] & testBits) == testValue)
364 else if(startY1 >= 0 && endY1 < 0)
369 if((right[testByte] & testBits) == testValue)
376 else if(startY2 >= 0 && endY2 < 0)
383 if ( ( endY2 > 0 ) && ( endY1 > 0 ) )
389 mStretchBorders.x = startX1;
390 mStretchBorders.y = startY1;
391 mStretchBorders.z = mWidth-endX1;
392 mStretchBorders.w = mHeight-endY1;
394 mChildRectangle.x = startX2;
395 mChildRectangle.y = startY2;
396 mChildRectangle.width = endX2-startX2;
397 mChildRectangle.height = endY2-startY2;
399 mParsedBorder = true;
403 } // namespace Internal