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 <dali/public-api/object/type-registry.h>
23 #include <dali/integration-api/bitmap.h>
24 #include <dali/internal/event/images/bitmap-external.h>
25 #include <dali/internal/event/common/thread-local-storage.h>
26 #include <dali/internal/event/resources/resource-client.h>
27 #include <dali/internal/update/manager/update-manager.h>
28 #include <dali/internal/event/images/image-factory.h>
29 #include <dali/integration-api/platform-abstraction.h>
30 #include <dali/integration-api/resource-types.h>
31 #include <dali/integration-api/resource-cache.h>
36 void GetRedOffsetAndMask(Dali::Pixel::Format pixelFormat, int& byteOffset, int& bitMask)
42 case Dali::Pixel::LA88:
49 case Dali::Pixel::RGB888:
50 case Dali::Pixel::RGB8888:
51 case Dali::Pixel::RGBA8888:
57 case Dali::Pixel::BGR8888:
58 case Dali::Pixel::BGRA8888:
64 case Dali::Pixel::RGB565:
70 case Dali::Pixel::BGR565:
77 case Dali::Pixel::RGBA4444:
83 case Dali::Pixel::BGRA4444:
90 case Dali::Pixel::RGBA5551:
97 case Dali::Pixel::BGRA5551:
104 case Dali::Pixel::COMPRESSED_R11_EAC:
105 case Dali::Pixel::COMPRESSED_SIGNED_R11_EAC:
106 case Dali::Pixel::COMPRESSED_RG11_EAC:
107 case Dali::Pixel::COMPRESSED_SIGNED_RG11_EAC:
108 case Dali::Pixel::COMPRESSED_RGB8_ETC2:
109 case Dali::Pixel::COMPRESSED_SRGB8_ETC2:
110 case Dali::Pixel::COMPRESSED_RGB8_ETC1:
111 case Dali::Pixel::COMPRESSED_RGB_PVRTC_4BPPV1:
112 case Dali::Pixel::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
113 case Dali::Pixel::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
114 case Dali::Pixel::COMPRESSED_RGBA8_ETC2_EAC:
115 case Dali::Pixel::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
117 DALI_LOG_ERROR("Pixel formats for compressed images are not compatible with simple masking-out of per-pixel alpha.\n");
125 } // anonymous namespace
135 TypeRegistration mType( typeid( Dali::NinePatchImage ), typeid( Dali::Image ), NULL );
136 } // unnamed namespace
138 NinePatchImagePtr NinePatchImage::New( const std::string& filename, const Dali::ImageAttributes& attributes, ReleasePolicy releasePol )
140 Internal::NinePatchImagePtr internal( new NinePatchImage( filename, attributes, releasePol ) );
141 internal->Initialize();
145 NinePatchImage::NinePatchImage( const std::string& filename, const Dali::ImageAttributes& attributes, ReleasePolicy releasePol)
146 : ResourceImage( IMAGE_LOAD_POLICY_DEFAULT, releasePol ),
149 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
150 mResourceClient = &tls.GetResourceClient();
152 Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction();
155 platformAbstraction.GetClosestImageSize( filename, attributes, closestSize );
156 ImageAttributes loadedAttrs;
157 loadedAttrs.SetSize( closestSize );
158 mWidth = closestSize.width;
159 mHeight = closestSize.height;
161 Integration::BitmapResourceType resourceType( loadedAttrs );
163 // Note, bitmap is only destroyed when the image is destroyed.
164 Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously(resourceType, filename);
167 mBitmap = static_cast<Integration::Bitmap*>( resource.Get());
175 NinePatchImage* NinePatchImage::DownCast( Image* image)
177 return dynamic_cast<NinePatchImage*>(image);
180 NinePatchImage::~NinePatchImage()
184 Vector4 NinePatchImage::GetStretchBorders()
186 if( ! mParsedBorder )
190 return mStretchBorders;
193 Rect<int> NinePatchImage::GetChildRectangle()
195 if( ! mParsedBorder )
199 return mChildRectangle;
202 Internal::BitmapImagePtr NinePatchImage::CreateCroppedBitmapImage()
204 BitmapImagePtr cropped;
208 DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n");
212 Pixel::Format pixelFormat = mBitmap->GetPixelFormat();
214 cropped = BitmapImage::New( mWidth-2, mHeight-2, pixelFormat, Dali::Image::NEVER );
216 Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile();
217 DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap");
221 PixelBuffer* destPixels = cropped->GetBuffer();
222 unsigned int destStride = cropped->GetBufferStride();
223 unsigned int pixelWidth = GetBytesPerPixel(pixelFormat);
225 PixelBuffer* srcPixels = mBitmap->GetBuffer();
226 unsigned int srcStride = srcProfile->GetBufferStride();
228 for( unsigned int row=1; row < mHeight-1; ++row )
230 PixelBuffer* src = srcPixels + row*srcStride + pixelWidth;
231 PixelBuffer* dest = destPixels + (row-1)*destStride;
232 memcpy(dest, src, destStride );
237 cropped->Update(area); // default area has no width or height
242 void NinePatchImage::Connect()
248 const ImageTicketPtr& t = mResourceClient->AddBitmapImage(mBitmap.Get());
250 mTicket->AddObserver(*this);
257 void NinePatchImage::Disconnect()
259 if( mConnectionCount > 0 )
266 void NinePatchImage::ParseBorders()
270 DALI_LOG_ERROR( "NinePatchImage: Bitmap not loaded, cannot perform operation\n");
274 Pixel::Format pixelFormat = mBitmap->GetPixelFormat();
276 Integration::Bitmap::PackedPixelsProfile* srcProfile = mBitmap->GetPackedPixelsProfile();
277 DALI_ASSERT_DEBUG( srcProfile && "Wrong profile for source bitmap");
281 unsigned int pixelWidth = GetBytesPerPixel(pixelFormat);
282 PixelBuffer* srcPixels = mBitmap->GetBuffer();
283 unsigned int srcStride = srcProfile->GetBufferStride();
287 Pixel::GetAlphaOffsetAndMask(pixelFormat, alphaByte, alphaBits);
290 GetRedOffsetAndMask(pixelFormat, redByte, redBits);
292 int testByte = alphaByte;
293 int testBits = alphaBits;
294 int testValue = alphaBits; // Opaque == stretch
299 testValue = 0; // Black == stretch
311 PixelBuffer* top = srcPixels + pixelWidth;
312 PixelBuffer* bottom = srcPixels + (mHeight-1)*srcStride + pixelWidth;
314 // Read the top and bottom rows:
315 // (Also read the last column to ensure end value gets set)
316 for( unsigned int col=1; col < mWidth; ++col )
318 if( (top[testByte] & testBits) == testValue )
325 else if(startX1 >= 0 && endX1 < 0)
330 if( (bottom[testByte] & testBits) == testValue )
337 else if(startX2 >= 0 && endX2 < 0)
342 if ( ( endX2 > 0 ) && ( endX1 > 0 ) )
351 // Read the left and right columns:
352 PixelBuffer* left = srcPixels + srcStride;
353 PixelBuffer* right = left + (srcStride - pixelWidth);
355 // (Also read the last row to ensure end value gets set)
356 for( unsigned int row=1; row < mHeight; ++row )
358 if((left[testByte] & testBits) == testValue)
365 else if(startY1 >= 0 && endY1 < 0)
370 if((right[testByte] & testBits) == testValue)
377 else if(startY2 >= 0 && endY2 < 0)
384 if ( ( endY2 > 0 ) && ( endY1 > 0 ) )
390 mStretchBorders.x = startX1;
391 mStretchBorders.y = startY1;
392 mStretchBorders.z = mWidth-endX1;
393 mStretchBorders.w = mHeight-endY1;
395 mChildRectangle.x = startX2;
396 mChildRectangle.y = startY2;
397 mChildRectangle.width = endX2-startX2;
398 mChildRectangle.height = endY2-startY2;
400 mParsedBorder = true;
404 } // namespace Internal