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 Dali::ImageAttributes& attributes, ReleasePolicy releasePol )
143 Internal::NinePatchImagePtr internal( new NinePatchImage( filename, attributes, releasePol ) );
144 internal->Initialize();
148 NinePatchImage::NinePatchImage( const std::string& filename, const Dali::ImageAttributes& attributes, ReleasePolicy releasePol)
149 : ResourceImage( IMAGE_LOAD_POLICY_DEFAULT, releasePol ),
152 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
153 mResourceClient = &tls.GetResourceClient();
155 Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction();
158 platformAbstraction.GetClosestImageSize( filename, attributes, closestSize );
159 ImageAttributes loadedAttrs;
160 loadedAttrs.SetSize( closestSize );
161 mWidth = closestSize.width;
162 mHeight = closestSize.height;
164 Integration::BitmapResourceType resourceType( loadedAttrs );
166 // Note, bitmap is only destroyed when the image is destroyed.
167 Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously(resourceType, filename);
170 mBitmap = static_cast<Integration::Bitmap*>( resource.Get());
178 NinePatchImage* NinePatchImage::DownCast( Image* image)
180 return dynamic_cast<NinePatchImage*>(image);
183 NinePatchImage::~NinePatchImage()
187 Vector4 NinePatchImage::GetStretchBorders()
189 if( ! mParsedBorder )
193 return mStretchBorders;
196 Rect<int> NinePatchImage::GetChildRectangle()
198 if( ! mParsedBorder )
202 return mChildRectangle;
205 Internal::BufferImagePtr NinePatchImage::CreateCroppedBufferImage()
207 BufferImagePtr cropped;
211 DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n");
215 Pixel::Format pixelFormat = mBitmap->GetPixelFormat();
217 cropped = BufferImage::New( mWidth-2, mHeight-2, pixelFormat, Dali::Image::NEVER );
219 Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile();
220 DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap");
224 PixelBuffer* destPixels = cropped->GetBuffer();
225 unsigned int destStride = cropped->GetBufferStride();
226 unsigned int pixelWidth = GetBytesPerPixel(pixelFormat);
228 PixelBuffer* srcPixels = mBitmap->GetBuffer();
229 unsigned int srcStride = srcProfile->GetBufferStride();
231 for( unsigned int row=1; row < mHeight-1; ++row )
233 PixelBuffer* src = srcPixels + row*srcStride + pixelWidth;
234 PixelBuffer* dest = destPixels + (row-1)*destStride;
235 memcpy(dest, src, destStride );
240 cropped->Update(area); // default area has no width or height
245 void NinePatchImage::Connect()
251 const ImageTicketPtr& t = mResourceClient->AddBitmapImage(mBitmap.Get());
253 mTicket->AddObserver(*this);
260 void NinePatchImage::Disconnect()
262 if( mConnectionCount > 0 )
269 void NinePatchImage::ParseBorders()
273 DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n");
277 Pixel::Format pixelFormat = mBitmap->GetPixelFormat();
279 Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile();
280 DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap");
284 unsigned int pixelWidth = GetBytesPerPixel(pixelFormat);
285 PixelBuffer* srcPixels = mBitmap->GetBuffer();
286 unsigned int srcStride = srcProfile->GetBufferStride();
290 Pixel::GetAlphaOffsetAndMask(pixelFormat, alphaByte, alphaBits);
293 GetRedOffsetAndMask(pixelFormat, redByte, redBits);
295 int testByte = alphaByte;
296 int testBits = alphaBits;
297 int testValue = alphaBits; // Opaque == stretch
302 testValue = 0; // Black == stretch
314 PixelBuffer* top = srcPixels + pixelWidth;
315 PixelBuffer* bottom = srcPixels + (mHeight-1)*srcStride + pixelWidth;
317 // Read the top and bottom rows:
318 // (Also read the last column to ensure end value gets set)
319 for( unsigned int col=1; col < mWidth; ++col )
321 if( (top[testByte] & testBits) == testValue )
328 else if(startX1 >= 0 && endX1 < 0)
333 if( (bottom[testByte] & testBits) == testValue )
340 else if(startX2 >= 0 && endX2 < 0)
345 if ( ( endX2 > 0 ) && ( endX1 > 0 ) )
354 // Read the left and right columns:
355 PixelBuffer* left = srcPixels + srcStride;
356 PixelBuffer* right = left + (srcStride - pixelWidth);
358 // (Also read the last row to ensure end value gets set)
359 for( unsigned int row=1; row < mHeight; ++row )
361 if((left[testByte] & testBits) == testValue)
368 else if(startY1 >= 0 && endY1 < 0)
373 if((right[testByte] & testBits) == testValue)
380 else if(startY2 >= 0 && endY2 < 0)
387 if ( ( endY2 > 0 ) && ( endY1 > 0 ) )
393 mStretchBorders.x = startX1;
394 mStretchBorders.y = startY1;
395 mStretchBorders.z = mWidth-endX1;
396 mStretchBorders.w = mHeight-endY1;
398 mChildRectangle.x = startX2;
399 mChildRectangle.y = startY2;
400 mChildRectangle.width = endX2-startX2;
401 mChildRectangle.height = endY2-startY2;
403 mParsedBorder = true;
407 } // namespace Internal