Project

General

Profile

SO3Engine
SO3EmbeddedWebNavigatorRenderHandler.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2011 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21-----------------------------------------------------------------------------
22*/
23
28#if SO3_WEB_NAVIGATOR_BUILD == 1
29
30namespace SO3
31{
32 namespace EmbeddedWebNavigator
33 {
34
35 WebNavigatorRenderHandler::WebNavigatorRenderHandler(CefRefPtr<WebNavigatorClient>& parentWebNavigatorClientInstance, const ScolWindowHandle& scolMainWindow, bool offscreen) : WebNavigatorHandler(parentWebNavigatorClientInstance, scolMainWindow),
36 isOffscreen(offscreen)
37 {
38 offscreenBuffer = 0;
39 offscreenBufferMemorySize = 0;
40 offscreenBuffer_width = 512;
41 offscreenBuffer_height = 512;
42 offscreenPopupBuffer = 0;
43 offscreenPopupRect.Set(0, 0, 0, 0);
44 bufferContentChanged = false;
45 }
46
47 WebNavigatorRenderHandler::WebNavigatorRenderHandler() : WebNavigatorHandler(CefRefPtr<WebNavigatorClient>(), 0),
48 isOffscreen(false)
49 {
50 // Forbidden ctor
51 }
52
54 {
55 if (offscreenBuffer)
56 {
57 free(offscreenBuffer);
58 offscreenBuffer = 0;
59 offscreenBufferMemorySize = 0;
60 }
61 if (offscreenPopupBuffer)
62 {
63 free(offscreenPopupBuffer);
64 offscreenPopupBuffer = 0;
65 offscreenPopupRect.Set(0, 0, 0, 0);
66 }
67 }
68
70 {
71 bufferContentChanged = false;
72 if (isOffscreen)
73 return offscreenBuffer;
74 else
75 return 0;
76 }
77
79 {
80 bufferContentChanged = false;
81 if (isOffscreen)
82 return offscreenPopupBuffer;
83 else
84 return 0;
85 }
86
87 bool WebNavigatorRenderHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect)
88 {
89 assert(CefCurrentlyOn(TID_UI));
90 if (isOffscreen && parentWebNavigator)
91 {
92 std::pair<int, int> size = parentWebNavigator->GetSize();
93 rect.x = rect.y = 0;
94 rect.width = size.first;
95 rect.height = size.second;
96 return true;
97 }
98 return false;
99 }
100
101 void WebNavigatorRenderHandler::OnPopupShow(CefRefPtr<CefBrowser> browser, bool show)
102 {
103 // Check cef current thread
104 assert(CefCurrentlyOn(TID_UI));
105
106 if (isOffscreen && (parentWebNavigatorClient.get() != 0))
107 {
108 //conditional lock
109 std::unique_lock< std::shared_mutex > lock(offscreenBufferCriticalSection);
110
111 if (!show)
112 {
113 // Clear the popup buffer.
114 offscreenPopupRect.Set(0, 0, 0, 0);
115 if (offscreenPopupBuffer != 0)
116 {
117 // Release memory
118 free(offscreenPopupBuffer);
119 offscreenPopupBuffer = 0;
120
121 // User texture will need refresh
122 bufferContentChanged = true;
123 }
124 }
125 }
126 }
127
128 void WebNavigatorRenderHandler::OnPopupSize(CefRefPtr<CefBrowser> browser, const CefRect& rect)
129 {
130 // Check cef current thread
131 assert(CefCurrentlyOn(TID_UI));
132
133 if (isOffscreen && (parentWebNavigatorClient.get() != 0))
134 {
135 //conditional lock
136 std::unique_lock< std::shared_mutex > lock(offscreenBufferCriticalSection);
137
138 if (rect.width > 0)
139 {
140 // It will always be inside the view due to HandleGetRect().
141 assert(((rect.x + rect.width) < static_cast<int>(offscreenBuffer_width)) && ((rect.y + rect.height) < static_cast<int>(offscreenBuffer_height)));
142
143 // Check the new size
144 if ((offscreenPopupRect.width * offscreenPopupRect.height) != (rect.width * rect.height))
145 {
146 // Delete existing buffer
147 if (offscreenPopupBuffer != 0)
148 free(offscreenPopupBuffer);
149
150 // Create a new buffer
151 size_t neededMemory = rect.width * rect.height * 4;
152 offscreenPopupBuffer = (unsigned char*)malloc(neededMemory);
153 memset(offscreenPopupBuffer, 0xF, neededMemory);
154 }
155
156 // Update the popup rectange.
157 offscreenPopupRect = rect;
158 }
159 }
160 }
161
162 void WebNavigatorRenderHandler::OnPaint(CefRefPtr<CefBrowser> browser, CefRenderHandler::PaintElementType type, const CefRenderHandler::RectList& dirtyRects, const void* buffer, int width, int height)
163 {
164 if (isOffscreen && (parentWebNavigatorClient.get() != 0))
165 {
166 //conditional lock
167 std::unique_lock< std::shared_mutex > lock(offscreenBufferCriticalSection);
168 if (!dirtyRects.empty())
169 {
170 assert(CefCurrentlyOn(TID_UI));
171
172 if (type == PET_VIEW)
173 {
174 // Paint the view.
175 SetRGB(browser, width, height, buffer, dirtyRects);
176 bufferContentChanged = true;
177 }
178
179 if (type == PET_POPUP)
180 {
181 // Store the popup in our dedicated buffer.
182 if (offscreenPopupBuffer != 0)
183 memcpy(offscreenPopupBuffer, (unsigned char*)buffer, offscreenPopupRect.width * offscreenPopupRect.height * 4);
184 }
185 }
186 }
187 }
188
189 void WebNavigatorRenderHandler::OnCursorChange(CefRefPtr<CefBrowser> browser, CefCursorHandle cursor, CursorType type, const CefCursorInfo& custom_cursor_info)
190 {
191 if (isOffscreen && parentWebNavigator)
192 {
193 assert(CefCurrentlyOn(TID_UI));
194
195 // Send event
196 std::unique_lock< std::shared_mutex > lock(WebNavigatorManager::GetSingletonPtr()->webMessageQueueCriticalSection);
198 }
199 }
200
201 void WebNavigatorRenderHandler::SetRGB(CefRefPtr<CefBrowser> browser, int width, int height, const void* src, const RectList& dirtyRects)
202 {
203 SetBufferSize(width, height);
204 ConvertToRGBA((unsigned char*)src, offscreenBuffer, dirtyRects, width, height);
205 }
206
208 {
209 return offscreenBuffer_width;
210 }
211
213 {
214 return offscreenBuffer_height;
215 }
216
218 {
219 return bufferContentChanged;
220 }
221
223 {
224 return offscreenPopupRect;
225 }
226
227 void WebNavigatorRenderHandler::SetBufferSize(int width, int height)
228 {
229 size_t dst_size = width * height * 4 * sizeof(unsigned char);
230
231 // Allocate a new buffer if necesary.
232 offscreenBuffer_width = width;
233 offscreenBuffer_height = height;
234
235 if (dst_size != offscreenBufferMemorySize)
236 {
237 if (offscreenBuffer)
238 free(offscreenBuffer);
239
240 offscreenBufferMemorySize = dst_size;
241 offscreenBuffer = (unsigned char*)malloc(offscreenBufferMemorySize);
242 memset(offscreenBuffer, 0xF, offscreenBufferMemorySize);
243 }
244 }
245
246 void WebNavigatorRenderHandler::ConvertToRGBA(const unsigned char* src, unsigned char* dst, const RectList& dirtyRects, int renderSizeWidth, int renderSizeHeight)
247 {
248 // Update all dirty regions
249 RectList::const_iterator iDirtyRects = dirtyRects.begin();
250 while (iDirtyRects != dirtyRects.end())
251 {
252 // Position the buffer pointer to the start of the dirty region
253 size_t initialOffset = ((((*iDirtyRects).y * renderSizeWidth) + (*iDirtyRects).x)) * 4;
254 size_t offset = initialOffset;
255
256 // Update one dirty region
257 for (int i = 0; i < (*iDirtyRects).height; i++)
258 {
259 memcpy(dst + offset, src + offset, (*iDirtyRects).width * 4);
260 offset += (renderSizeWidth * 4);
261 }
262
263 // Next dirty region
264 iDirtyRects++;
265 }
266 }
267
272
273 bool WebNavigatorRenderHandler::BlitOffscreenBitmap(unsigned char* dest, int destWidth, int destHeight, int destBytesPerPixel, int destBitsPerLine)
274 {
275 bool result = false;
276 std::shared_lock< std::shared_mutex > lock(offscreenBufferCriticalSection);
277
278 if ((offscreenBuffer_width == destWidth) && (offscreenBuffer_height == destHeight))
279 {
280 // Vars used for blitting
281 unsigned long srcByte = 0;
282 unsigned long destByte = 0;
283
284 // Get and blit main view buffer
285 unsigned char* buffer = GetOffscreenBuffer();
286 if (buffer != 0)
287 {
288 for (long y = 0; y < destHeight; y++)
289 {
290 for (long x = 0; x < destWidth; x++)
291 {
292 srcByte = (x + (destWidth * y)) * 4;
293 destByte = (x * destBytesPerPixel) + (y * destBitsPerLine);
294
295 dest[destByte] = buffer[srcByte];
296 dest[destByte + 1] = buffer[srcByte + 1];
297 dest[destByte + 2] = buffer[srcByte + 2];
298 }
299 }
300 }
301
302 // Get and blit secondary buffer ('popup' buffer).
303 buffer = GetOffscreenPopupBuffer();
304 CefRect offscreenPopupBufferRect = GetOffscreenPopupBufferRect();
305 if (buffer != 0)
306 {
307 for (long y = 0; y < offscreenPopupBufferRect.height; y++)
308 {
309 for (long x = 0; x < offscreenPopupBufferRect.width; x++)
310 {
311 srcByte = (x + (y * offscreenPopupBufferRect.width)) * 4;
312 destByte = ((x + offscreenPopupBufferRect.x) * destBytesPerPixel) + ((offscreenPopupBufferRect.y + y) * destBitsPerLine);
313
314 dest[destByte] = buffer[srcByte];
315 dest[destByte + 1] = buffer[srcByte + 1];
316 dest[destByte + 2] = buffer[srcByte + 2];
317 }
318 }
319 }
320
321 // All done
322 result = true;
323 }
324 return result;
325 }
326
327 bool WebNavigatorRenderHandler::BlitOffscreenAlphaBitmap(unsigned char* destColor, unsigned char* destAlpha, int destWidth, int destHeight, int destColorBytesPerPixel, int destColorBitsPerLine)
328 {
329 bool result = false;
330 std::shared_lock< std::shared_mutex > lock(offscreenBufferCriticalSection);
331
332 if ((offscreenBuffer_width == destWidth) && (offscreenBuffer_height == destHeight))
333 {
334 // Vars used for blitting
335 unsigned long srcByte = 0;
336 unsigned long destByte = 0;
337 unsigned long alphaLineOffset = 0;
338
339 // Get and blit main view buffer
340 unsigned char* buffer = GetOffscreenBuffer();
341 if (buffer != 0)
342 {
343 for (long y = 0; y < destHeight; y++)
344 {
345 alphaLineOffset = y * destWidth;
346 for (long x = 0; x < destWidth; x++)
347 {
348 srcByte = (x + (y * destWidth)) * 4;
349 destByte = (x * destColorBytesPerPixel) + (y * destColorBitsPerLine);
350
351 destColor[destByte] = buffer[srcByte];
352 destColor[destByte + 1] = buffer[srcByte + 1];
353 destColor[destByte + 2] = buffer[srcByte + 2];
354 destAlpha[x + alphaLineOffset] = buffer[srcByte + 3];
355 }
356 }
357 }
358
359 // Get and blit secondary buffer ('popup' buffer).
360 buffer = GetOffscreenPopupBuffer();
361 CefRect offscreenPopupBufferRect = GetOffscreenPopupBufferRect();
362 if (buffer != 0)
363 {
364 for (long y = 0; y < offscreenPopupBufferRect.height; y++)
365 {
366 alphaLineOffset = (y * offscreenPopupBufferRect.width);
367 for (long x = 0; x < offscreenPopupBufferRect.width; x++)
368 {
369 srcByte = (x + (y * offscreenPopupBufferRect.width)) * 4;
370 destByte = ((x + offscreenPopupBufferRect.x) * destColorBytesPerPixel) + ((offscreenPopupBufferRect.y + y) * destColorBitsPerLine);
371
372 destColor[destByte] = buffer[srcByte];
373 destColor[destByte + 1] = buffer[srcByte + 1];
374 destColor[destByte + 2] = buffer[srcByte + 2];
375 destAlpha[x + alphaLineOffset] = buffer[srcByte + 3];
376 }
377 }
378 }
379
380 // All done
381 result = true;
382 }
383 return result;
384 }
385
386 bool WebNavigatorRenderHandler::BlitOffscreenTexture(Ogre::TexturePtr& ogreTexture, bool forceUpdate)
387 {
388 bool returnValue = false;
389 if (forceUpdate || bufferContentChanged)
390 {
391 // Lock render handler buffer
392 std::shared_lock< std::shared_mutex > lock(offscreenBufferCriticalSection);
393 try
394 {
395 // Lock the pixel buffer and get a pixel box
396 Ogre::HardwarePixelBufferSharedPtr pixelBuffer = ogreTexture->getBuffer();
397 pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
398 const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();
399
400 // Get and blit main view buffer
401 unsigned char* cefRenderBuffer = GetOffscreenBuffer();
402 if (cefRenderBuffer != 0)
403 {
404 // Create an Ogre pixel box for easy streching.
405 const Ogre::PixelBox scolPixelBox(offscreenBuffer_width, offscreenBuffer_height, 1, Ogre::PF_BYTE_BGRA, cefRenderBuffer);
406
407 // Streching bitmap data to Ogre texture size. Nb that the scale function takes an optional filter parameter if we wants other filtering than bilinear
408 Ogre::Image::scale(scolPixelBox, pixelBox);
409 }
410
411 // Get and blit secondary buffer ('popup' buffer).
412 cefRenderBuffer = GetOffscreenPopupBuffer();
413 CefRect offscreenPopupBufferRect = GetOffscreenPopupBufferRect();
414 if (cefRenderBuffer != 0)
415 {
416 float ratio = static_cast<float>(pixelBox.getWidth()) / static_cast<float>(offscreenBuffer_width);
417 Ogre::PixelBox targetPixelBox = pixelBox.getSubVolume(Ogre::Box(static_cast<size_t>(offscreenPopupBufferRect.x * ratio),
418 static_cast<size_t>(offscreenPopupBufferRect.y * ratio),
419 static_cast<size_t>((offscreenPopupBufferRect.width + offscreenPopupBufferRect.x) * ratio),
420 static_cast<size_t>((offscreenPopupBufferRect.height + offscreenPopupBufferRect.y) * ratio)));
421
422 // Create an Ogre pixel box for easy streching.
423 const Ogre::PixelBox scolPixelBox(offscreenPopupBufferRect.width, offscreenPopupBufferRect.height, 1, Ogre::PF_BYTE_BGRA, cefRenderBuffer);
424
425 // Streching bitmap data to Ogre texture size. Nb that the scale function takes an optional filter parameter if we wants other filtering than bilinear
426 Ogre::Image::scale(scolPixelBox, targetPixelBox);
427 }
428
429 // Everything is ok
430 pixelBuffer->unlock();
431 returnValue = true;
432 }
433 catch (const Ogre::Exception&)
434 {
435 // Problem!
436 }
437 }
438 return returnValue;
439 }
440
441 bool WebNavigatorRenderHandler::CheckPixelAlpha(int posX, int posY, float transparentTresholdColor)
442 {
443 bool returnValue = false;
444
445 if (GetOffscreenBuffer() && (posX < static_cast<int>(offscreenBuffer_width)) && (posY < static_cast<int>(offscreenBuffer_height)))
446 {
447 std::shared_lock< std::shared_mutex > lock(offscreenBufferCriticalSection);
448 unsigned char* buf = GetOffscreenBuffer();
449 int color = buf[(((posX * 4) + (offscreenBuffer_width * 4) * posY) + 3) * sizeof(unsigned char)];
450 if (color > transparentTresholdColor * 255)
451 returnValue = true;
452 }
453 return returnValue;
454 }
455
456 }
457}
458
459#endif
void InvokeCursorChange(unsigned long uniqueId, HCURSOR newCursor)
virtual void OnPopupShow(CefRefPtr< CefBrowser > browser, bool show) OVERRIDE
virtual bool GetViewRect(CefRefPtr< CefBrowser > browser, CefRect &rect)
virtual void OnCursorChange(CefRefPtr< CefBrowser > browser, CefCursorHandle cursor, CursorType type, const CefCursorInfo &custom_cursor_info) OVERRIDE
virtual void OnPaint(CefRefPtr< CefBrowser > browser, CefRenderHandler::PaintElementType type, const CefRenderHandler::RectList &dirtyRects, const void *buffer, int width, int height) OVERRIDE
bool BlitOffscreenTexture(Ogre::TexturePtr &ogreTexture, bool forceUpdate)
bool BlitOffscreenBitmap(unsigned char *dest, int destWidth, int destHeight, int destBytesPerPixel, int destBitsPerLine)
virtual void OnPopupSize(CefRefPtr< CefBrowser > browser, const CefRect &rect) OVERRIDE
bool CheckPixelAlpha(int posX, int posY, float transparentTresholdColor)
bool BlitOffscreenAlphaBitmap(unsigned char *destColor, unsigned char *destAlpha, int destWidth, int destHeight, int destColorBytesPerPixel, int destColorBitsPerLine)