Skip to content

Commit 3b30ecc

Browse files
committed
Add support for displaying dropdown boxes in Interact mode.
1 parent 9ce0c9e commit 3b30ecc

File tree

5 files changed

+173
-17
lines changed

5 files changed

+173
-17
lines changed

obs-browser/browser-render-handler.cpp

Lines changed: 95 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,31 @@ BrowserRenderHandler::~BrowserRenderHandler()
3535
surfaceHandles.clear();
3636
}
3737

38+
void BrowserRenderHandler::OnPopupSize(CefRefPtr<CefBrowser> browser,
39+
const CefRect& rect)
40+
{
41+
if (rect.width <= 0 || rect.height <= 0)
42+
return;
43+
44+
originalPopupRect = rect;
45+
popupRect = GetPopupRectInWebView(originalPopupRect);
46+
}
47+
48+
void BrowserRenderHandler::OnPopupShow(CefRefPtr<CefBrowser> browser,
49+
bool show)
50+
{
51+
if (!show)
52+
{
53+
ClearPopupRects();
54+
browserListener->DestroyPopupSurface();
55+
}
56+
}
57+
58+
void BrowserRenderHandler::ClearPopupRects() {
59+
popupRect.Set(0, 0, 0, 0);
60+
originalPopupRect.Set(0, 0, 0, 0);
61+
}
62+
3863
bool
3964
BrowserRenderHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect &rect)
4065
{
@@ -44,37 +69,90 @@ BrowserRenderHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect &rect)
4469
return true;
4570
}
4671

47-
72+
CefRect BrowserRenderHandler::GetPopupRectInWebView(const CefRect& originalRect)
73+
{
74+
CefRect rc(originalRect);
75+
// if x or y are negative, move them to 0.
76+
if (rc.x < 0)
77+
rc.x = 0;
78+
if (rc.y < 0)
79+
rc.y = 0;
80+
// if popup goes outside the view, try to reposition origin
81+
if (rc.x + rc.width > width)
82+
rc.x = width - rc.width;
83+
if (rc.y + rc.height > height)
84+
rc.y = height - rc.height;
85+
// if x or y became negative, move them to 0 again.
86+
if (rc.x < 0)
87+
rc.x = 0;
88+
if (rc.y < 0)
89+
rc.y = 0;
90+
return rc;
91+
}
4892

4993
void BrowserRenderHandler::OnPaint(CefRefPtr<CefBrowser> browser,
5094
PaintElementType type, const RectList &dirtyRects,
5195
const void *data, int width, int height)
5296
{
5397
(void)browser;
54-
(void)type;
55-
(void)dirtyRects;
5698

99+
if (type == PET_VIEW)
100+
{
101+
viewWidth = width;
102+
viewHeight = height;
103+
if (surfaceHandles.size() < 2) {
104+
BrowserSurfaceHandle newSurfaceHandle = 0;
105+
browserListener->CreateSurface(width, height,
106+
&newSurfaceHandle);
107+
108+
if (newSurfaceHandle != nullptr) {
109+
surfaceHandles.push_back(newSurfaceHandle);
110+
}
111+
}
112+
113+
int previousSurfaceHandle = currentSurfaceHandle;
57114

58-
if (surfaceHandles.size() < 2) {
59-
BrowserSurfaceHandle newSurfaceHandle = 0;
60-
browserListener->CreateSurface(width, height,
61-
&newSurfaceHandle);
115+
currentSurfaceHandle = (++currentSurfaceHandle % surfaceHandles.size());
62116

63-
if (newSurfaceHandle != nullptr) {
64-
surfaceHandles.push_back(newSurfaceHandle);
117+
if (currentSurfaceHandle != previousSurfaceHandle) {
118+
obs_enter_graphics();
119+
gs_texture_set_image(surfaceHandles[currentSurfaceHandle],
120+
(const uint8_t*)data, width * 4, false);
121+
obs_leave_graphics();
65122
}
66123
}
67-
68-
int previousSurfaceHandle = currentSurfaceHandle;
69-
70-
currentSurfaceHandle = (++currentSurfaceHandle % surfaceHandles.size());
124+
else if (type == PET_POPUP && popupRect.width > 0 &&
125+
popupRect.height > 0)
126+
{
127+
int skipPixels = 0, x = popupRect.x;
128+
int skipRows = 0, y = popupRect.y;
129+
int w = width;
130+
int h = height;
131+
132+
if (x < 0)
133+
{
134+
skipPixels = -x;
135+
x = 0;
136+
}
71137

72-
if (currentSurfaceHandle != previousSurfaceHandle) {
138+
if (y < 0)
139+
{
140+
skipRows = -y;
141+
y = 0;
142+
}
143+
if (x + w > viewWidth)
144+
w -= x + w - viewWidth;
145+
if (y + h > viewHeight)
146+
h -= y + h - viewHeight;
147+
73148
obs_enter_graphics();
74-
gs_texture_set_image(surfaceHandles[currentSurfaceHandle],
75-
(const uint8_t*) data, width * 4, false);
149+
BrowserSurfaceHandle newTexture = 0;
150+
browserListener->CreatePopupSurface(width, height, x, y, &newTexture);
151+
gs_texture_set_image(newTexture,
152+
(const uint8_t*)data, w * 4, false);
76153
obs_leave_graphics();
77154
}
78155

79-
browserListener->OnDraw(surfaceHandles[currentSurfaceHandle], width, height);
156+
157+
browserListener->OnDraw(surfaceHandles[currentSurfaceHandle], viewWidth, viewHeight);
80158
}

obs-browser/browser-render-handler.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,36 @@ class BrowserRenderHandler : public CefRenderHandler
3939
virtual bool GetViewRect(CefRefPtr<CefBrowser> browser, CefRect &rect)
4040
OVERRIDE;
4141

42+
CefRect GetPopupRectInWebView(const CefRect& originalRect);
43+
4244
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
4345
PaintElementType type, const RectList &dirtyRects,
4446
const void *buffer, int width, int height) OVERRIDE;
4547

48+
const CefRect& popupRect_() const { return popupRect; }
49+
const CefRect& originalPopupRect_() const { return originalPopupRect; }
50+
51+
// Forwarded from CefRenderHandler callbacks.
52+
void OnPopupShow(CefRefPtr<CefBrowser> browser,
53+
bool show);
54+
// |rect| must be in pixel coordinates.
55+
void OnPopupSize(CefRefPtr<CefBrowser> browser,
56+
const CefRect& rect);
57+
void ClearPopupRects();
58+
59+
int GetViewWidth() const { return viewWidth; }
60+
int GetViewHeight() const { return viewHeight; }
61+
4662
private:
4763
const int width;
4864
const int height;
4965
const std::shared_ptr<BrowserListener> browserListener;
5066
std::vector<struct gs_texture *> surfaceHandles;
5167
int currentSurfaceHandle;
68+
int viewWidth;
69+
int viewHeight;
70+
CefRect popupRect;
71+
CefRect originalPopupRect;
5272

5373
private:
5474
IMPLEMENT_REFCOUNTING(BrowserRenderHandler);

obs-browser/browser-source-listener-base.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ void BrowserSource::Impl::Listener::OnDraw( BrowserSurfaceHandle surfaceHandle,
3030

3131
obs_enter_graphics();
3232
browserSource->GetParent()->LockTexture();
33+
if (popupSurface != nullptr)
34+
gs_copy_texture_region(surfaceHandle, popupX, popupY, popupSurface, 0, 0, gs_texture_get_width(popupSurface), gs_texture_get_height(popupSurface));
3335
browserSource->SetActiveTexture(surfaceHandle);
3436
browserSource->GetParent()->UnlockTexture();
3537
obs_leave_graphics();
@@ -60,6 +62,31 @@ bool BrowserSource::Impl::Listener::CreateSurface(int width, int height,
6062
return true;
6163
}
6264

65+
bool BrowserSource::Impl::Listener::CreatePopupSurface(int width, int height,
66+
int x, int y, BrowserSurfaceHandle *popupSurfaceHandle)
67+
{
68+
obs_enter_graphics();
69+
70+
gs_texture_t *newTexture = gs_texture_create(width, height, GS_BGRA, 1,
71+
nullptr, GS_DYNAMIC);
72+
73+
obs_leave_graphics();
74+
75+
*popupSurfaceHandle = newTexture;
76+
popupSurface = newTexture;
77+
popupX = x;
78+
popupY = y;
79+
80+
return true;
81+
}
82+
83+
void BrowserSource::Impl::Listener::DestroyPopupSurface()
84+
{
85+
obs_enter_graphics();
86+
popupSurface = nullptr;
87+
obs_leave_graphics();
88+
}
89+
6390
void BrowserSource::Impl::Listener::DestroySurface(
6491
BrowserSurfaceHandle surfaceHandle)
6592
{

obs-browser/browser-source-listener-base.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,18 @@ class BrowserSource::Impl::Listener : public BrowserListener
4646

4747
void DestroySurface(BrowserSurfaceHandle surfaceHandle);
4848

49+
bool CreatePopupSurface(
50+
int width,
51+
int height,
52+
int x,
53+
int y,
54+
BrowserSurfaceHandle *surfaceHandle);
55+
56+
void DestroyPopupSurface();
57+
4958
private:
5059
BrowserSource::Impl *browserSource;
60+
gs_texture_t *popupSurface = nullptr;
5161
std::set<BrowserSurfaceHandle> textureSet;
62+
int popupX, popupY;
5263
};

shared/browser-listener.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,26 @@ class BrowserListener : public BrowserListenerBase
5656
return false;
5757
}
5858

59+
virtual bool CreatePopupSurface(
60+
int width,
61+
int height,
62+
int x,
63+
int y,
64+
BrowserSurfaceHandle *surfaceHandle)
65+
{
66+
(void)width;
67+
(void)height;
68+
(void)x;
69+
(void)y;
70+
(void)surfaceHandle;
71+
72+
return false;
73+
}
74+
75+
virtual void DestroyPopupSurface()
76+
{
77+
}
78+
5979
virtual void DestroySurface(BrowserSurfaceHandle surfaceHandle) override
6080
{
6181
(void)surfaceHandle;

0 commit comments

Comments
 (0)