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/common/thread-local-storage.h>
28 #include <dali/internal/event/resources/resource-client.h>
29 #include <dali/internal/update/manager/update-manager.h>
30 #include <dali/internal/event/images/image-factory.h>
31 #include <dali/integration-api/platform-abstraction.h>
32 #include <dali/integration-api/resource-types.h>
33 #include <dali/integration-api/resource-cache.h>
38 void GetRedOffsetAndMask(Dali::Pixel::Format pixelFormat, int& byteOffset, int& bitMask)
44 case Dali::Pixel::LA88:
51 case Dali::Pixel::RGB888:
52 case Dali::Pixel::RGB8888:
53 case Dali::Pixel::RGBA8888:
59 case Dali::Pixel::BGR8888:
60 case Dali::Pixel::BGRA8888:
66 case Dali::Pixel::RGB565:
72 case Dali::Pixel::BGR565:
79 case Dali::Pixel::RGBA4444:
85 case Dali::Pixel::BGRA4444:
92 case Dali::Pixel::RGBA5551:
99 case Dali::Pixel::BGRA5551:
106 case Dali::Pixel::COMPRESSED_R11_EAC:
107 case Dali::Pixel::COMPRESSED_SIGNED_R11_EAC:
108 case Dali::Pixel::COMPRESSED_RG11_EAC:
109 case Dali::Pixel::COMPRESSED_SIGNED_RG11_EAC:
110 case Dali::Pixel::COMPRESSED_RGB8_ETC2:
111 case Dali::Pixel::COMPRESSED_SRGB8_ETC2:
112 case Dali::Pixel::COMPRESSED_RGB8_ETC1:
113 case Dali::Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
114 case Dali::Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
115 case Dali::Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
116 case Dali::Pixel::COMPRESSED_RGBA8_ETC2_EAC:
117 case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
119 DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple masking-out of per-pixel alpha.\n");
127 } // anonymous namespace
137 TypeRegistration mType( typeid( Dali::NinePatchImage ), typeid( Dali::Image ), NULL );
138 } // unnamed namespace
140 NinePatchImagePtr NinePatchImage::New( const std::string& filename, const ImageAttributes& attributes, ReleasePolicy releasePol )
142 Internal::NinePatchImagePtr internal( new NinePatchImage( filename, attributes, releasePol ) );
143 internal->Initialize();
147 NinePatchImage::NinePatchImage( const std::string& filename, const ImageAttributes& attributes, ReleasePolicy releasePol )
148 : ResourceImage( IMAGE_LOAD_POLICY_DEFAULT, releasePol ),
151 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
152 mResourceClient = &tls.GetResourceClient();
154 Integration::PlatformAbstraction& platformAbstraction = tls.GetPlatformAbstraction();
155 Integration::BitmapResourceType resourceType( ImageDimensions::FromFloatVec2( attributes.GetSize() ), attributes.GetScalingMode(), attributes.GetFilterMode(), attributes.GetOrientationCorrection() );
157 // Note, bitmap is only destroyed when the image is destroyed.
158 Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously( resourceType, filename );
161 mBitmap = static_cast<Integration::Bitmap*>( resource.Get());
162 mWidth = mBitmap->GetImageWidth();
163 mHeight = mBitmap->GetImageHeight();
173 NinePatchImage* NinePatchImage::DownCast( Image* image)
175 return dynamic_cast<NinePatchImage*>(image);
178 NinePatchImage::~NinePatchImage()
182 Vector4 NinePatchImage::GetStretchBorders()
184 if( ! mParsedBorder )
188 return mStretchBorders;
191 Rect<int> NinePatchImage::GetChildRectangle()
193 if( ! mParsedBorder )
197 return mChildRectangle;
200 Internal::BufferImagePtr NinePatchImage::CreateCroppedBufferImage()
202 BufferImagePtr cropped;
206 DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n");
210 Pixel::Format pixelFormat = mBitmap->GetPixelFormat();
212 cropped = BufferImage::New( mWidth-2, mHeight-2, pixelFormat, Dali::Image::NEVER );
214 Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile();
215 DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap");
219 PixelBuffer* destPixels = cropped->GetBuffer();
220 unsigned int destStride = cropped->GetBufferStride();
221 unsigned int pixelWidth = GetBytesPerPixel(pixelFormat);
223 PixelBuffer* srcPixels = mBitmap->GetBuffer();
224 unsigned int srcStride = srcProfile->GetBufferStride();
226 for( unsigned int row=1; row < mHeight-1; ++row )
228 PixelBuffer* src = srcPixels + row*srcStride + pixelWidth;
229 PixelBuffer* dest = destPixels + (row-1)*destStride;
230 memcpy(dest, src, destStride );
235 cropped->Update(area); // default area has no width or height
240 void NinePatchImage::Connect()
246 const ImageTicketPtr& t = mResourceClient->AddBitmapImage(mBitmap.Get());
248 mTicket->AddObserver(*this);
255 void NinePatchImage::Disconnect()
257 if( mConnectionCount > 0 )
264 void NinePatchImage::ParseBorders()
268 DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n");
272 Pixel::Format pixelFormat = mBitmap->GetPixelFormat();
274 Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile();
275 DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap");
279 unsigned int pixelWidth = GetBytesPerPixel(pixelFormat);
280 PixelBuffer* srcPixels = mBitmap->GetBuffer();
281 unsigned int srcStride = srcProfile->GetBufferStride();
285 Pixel::GetAlphaOffsetAndMask(pixelFormat, alphaByte, alphaBits);
288 GetRedOffsetAndMask(pixelFormat, redByte, redBits);
290 int testByte = alphaByte;
291 int testBits = alphaBits;
292 int testValue = alphaBits; // Opaque == stretch
297 testValue = 0; // Black == stretch
309 PixelBuffer* top = srcPixels + pixelWidth;
310 PixelBuffer* bottom = srcPixels + (mHeight-1)*srcStride + pixelWidth;
312 // Read the top and bottom rows:
313 // (Also read the last column to ensure end value gets set)
314 for( unsigned int col=1; col < mWidth; ++col )
316 if( (top[testByte] & testBits) == testValue )
323 else if(startX1 >= 0 && endX1 < 0)
328 if( (bottom[testByte] & testBits) == testValue )
335 else if(startX2 >= 0 && endX2 < 0)
340 if ( ( endX2 > 0 ) && ( endX1 > 0 ) )
349 // Read the left and right columns:
350 PixelBuffer* left = srcPixels + srcStride;
351 PixelBuffer* right = left + (srcStride - pixelWidth);
353 // (Also read the last row to ensure end value gets set)
354 for( unsigned int row=1; row < mHeight; ++row )
356 if((left[testByte] & testBits) == testValue)
363 else if(startY1 >= 0 && endY1 < 0)
368 if((right[testByte] & testBits) == testValue)
375 else if(startY2 >= 0 && endY2 < 0)
382 if ( ( endY2 > 0 ) && ( endY1 > 0 ) )
388 mStretchBorders.x = startX1;
389 mStretchBorders.y = startY1;
390 mStretchBorders.z = mWidth-endX1;
391 mStretchBorders.w = mHeight-endY1;
393 mChildRectangle.x = startX2;
394 mChildRectangle.y = startY2;
395 mChildRectangle.width = endX2-startX2;
396 mChildRectangle.height = endY2-startY2;
398 mParsedBorder = true;
402 } // namespace Internal