如何对来自 WebView 的changeAttributes: delegate pass-through做出有意义的反应?

发布于 2024-10-06 21:55:44 字数 1451 浏览 1 评论 0原文

WebView 通过 WebEditingDelegate 支持一种委托机制,可以为 WebView(或私有 >WebHTMLView) 接收。当 WebHTMLView 中接收到诸如以下的操作时

-(void)changeAttributes:(id)sender

,它会被传递到委托方法:

-(BOOL)webView:(WebView *)webView doCommandBySelector:(SEL)command

不幸的是,该机制不提供“sender”在独创的动作方法。

对于绝大多数操作,发送者并不重要,但对于changeAttributes 和changeFont 来说,合约要求接收者调用“sender”,以便例如convertAttributes:convertFont:

对于 changeFont 情况,事实证明,调用 [[NSFontManager sharedFontManager] ConvertFont:] 就足够了,巧合的是,这就是发送者。

changeAttributes 情况下,特别是当更改删除线时,发送者可能是一个私有类“NSFontEffectsBox”,它可能对应于负责的字体面板的子部分更改删除线/等设置。

不幸的是,调用 [[NSFontManagersharedFontManager]convertAttributes:] 无法获得预期的属性更改。这使得有兴趣有意义地实现此方法的委托人陷入了一个难题:

  1. WebKit 不传达发送者,因此委托人无法制定合同[sender ConvertAttributes:]调用。

  2. changeAttributes: 调用被发送到私有 WebKit 类 WebHTMLView,该类不能进行子类化,例如自定义 changeAttributes: 的行为。 code>.

  3. changeAttributes: 调用的发送方 NSFontEffectsBox 是一个私有类,无法以 [NSFontEffectsBox sharedFontEffectsBox] 等方式进行访问。< /p>

简而言之:开发人员似乎无法有意义地覆盖 WebViewchangeAttributes: 行为。

有什么想法吗?

WebView supports, through the WebEditingDelegate, a mechanism for the delegate to implement custom behavior for a variety of actions the WebView (or the private WebHTMLView) receives. When an action such as:

-(void)changeAttributes:(id)sender

is received in WebHTMLView, it is passed through to the delegate method:

-(BOOL)webView:(WebView *)webView doCommandBySelector:(SEL)command

Unfortunately, the mechanism does not provide for conveyance of the "sender" in the original action method.

For the vast majority of actions, the sender is unimportant, but for changeAttributes, and changeFont, for example, the contract requires that "sender" be called by the recipient in order to e.g. convertAttributes: or convertFont:.

For the changeFont case, it turns out that calling [[NSFontManager sharedFontManager] convertFont:] is sufficient, as coincidentally this is what the sender is.

In the changeAttributes case, in particular when strikethrough is changed, the sender may be a private class "NSFontEffectsBox" which presumably corresponds to the subsection of the font panel that is responsible for changing strikethrough/etc settings.

Unfortunately, calling [[NSFontManager sharedFontManager] convertAttributes:] does NOT obtain the expected attribute changes. This leaves a delegate who is interested in implementing this method meaningfully in a bit of a conundrum:

  1. WebKit does not convey the sender, so the delegate can't make the contractual [sender convertAttributes:] call.

  2. The changeAttributes: call is sent to a private WebKit class, WebHTMLView, which cannot be subclassed to, e.g., customize the behavior of changeAttributes:.

  3. The sender for the changeAttributes: call, NSFontEffectsBox, is a private class and cannot be accessed e.g. as [NSFontEffectsBox sharedFontEffectsBox].

In short: there appears to be no way for a developer to meaningfully override the behavior of changeAttributes: for a WebView.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不如归去 2024-10-13 21:55:44

这是一种邪恶的行为。一对适当的邪恶操作(它们都不是特别干净或理想)将是:

  1. 执行一些内联​​汇编程序来查找堆栈以从调用者的堆栈(或调用者的调用者,视情况而定)中读取发送者参数是)。当然,这是假设在调用 WebHTMLView 时,发送方位于堆栈上,而不是位于 %eax 中。然而,这将始终适用于 PowerPC 代码,因此它可能不会启动。

  2. WebHTMLView 上放置一个类别,其名称类似于 __my_evil_hacky_nasty_ugly_changeAttributes_thing: ,并在运行时使用 ObjC 运行时中的 method_exchangeImplementations() 将您的类别的实现与他们的实现交换。您的方法变为 changeAttributes:,他们的方法变为 __my_evil_hacky_nasty_ugly_changeAttributes_thing:,然后您可以调用该方法来传递原始调用。

正如我所说,两者都不是特别理想,但第二个具有完整运行时支持的优势(即运行时明确设计为让您执行此操作),并且由于您在运行时查找类和方法,所以它是失败的 -宽容。然而,在这种情况下失败会让你回到原点。

实际上,它需要针对 WebKit 记录一个错误,让它们传递给发件人,使其变得有意义。您的重写版本可能会查找方法 -(BOOL)webView:(WebView*)webView doCommandBySelector:(SEL)selector sender:(id)sender 并在找到时调用该方法,否则只需调用原来的方法。老实说,这就是苹果代码应该做的事情。

This is an evil one. A suitably evil pair of actions (neither of them particularly clean or ideal) would be:

  1. Do some inline assembler to look back up the stack to read the sender argument from the caller's stack (or the caller's caller, as the case should be). This of course assumes that the sender is placed on the stack and not in %eax when the call to WebHTMLView was made. That will always apply to PowerPC code however, so it's likely a non-starter there.

  2. Put a category on WebHTMLView with a method named something like __my_evil_hacky_nasty_ugly_changeAttributes_thing: and at runtime use method_exchangeImplementations() from the ObjC runtime to swap your category's implementation with theirs. Your method becomes changeAttributes: and theirs becomes __my_evil_hacky_nasty_ugly_changeAttributes_thing:, which you can then call to pass on the original call.

As I said, neither is particularly ideal, but the second has the advantage of full runtime support (i.e. the runtime is explicitly designed to let you do this), and since you're looking up the class and methods at runtime, it's failure-tolerant. Failure in this case gets you back to square one however.

Really it needs a bug logged against WebKit to have them pass on the sender to make it meaningful at all. Your overridden version could potentially look for a method -(BOOL)webView:(WebView*)webView doCommandBySelector:(SEL)selector sender:(id)sender and call that if found, otherwise just call through to the original method. This is what Apple's code should be doing, TBH.

梦行七里 2024-10-13 21:55:44

你看过源代码吗?

WebHTMLView.mm

我不明白 -changeAttributes:正在调用 -webView:doCommandBySelector:,因为在此类中,它仅在其自己的 -doCommandBySelector: 方法中调用。

- (void)changeAttributes:(id)sender
{
    [self _applyStyleToSelection:[self _styleForAttributeChange:sender] withUndoAction:EditActionChangeAttributes];
}


- (void)doCommandBySelector:(SEL)aSelector
{
…
    if (![[webView _editingDelegateForwarder] webView:webView doCommandBySelector:aSelector] && coreFrame) {
…
}

另外,为什么不能继承 WebHTMLView 呢?是因为Mac App Store对API的限制吗? WebKit 算私有吗?我以为它是开源的。

-威尔

Have you looked at the source code?

WebHTMLView.mm

I don't see how -changeAttributes: is calling -webView:doCommandBySelector:, as within this class it's only called inside its own -doCommandBySelector: method.

- (void)changeAttributes:(id)sender
{
    [self _applyStyleToSelection:[self _styleForAttributeChange:sender] withUndoAction:EditActionChangeAttributes];
}


- (void)doCommandBySelector:(SEL)aSelector
{
…
    if (![[webView _editingDelegateForwarder] webView:webView doCommandBySelector:aSelector] && coreFrame) {
…
}

Also, why can't you subclass WebHTMLView? Is it because of the Mac App Store restrictions on API? Does WebKit count as private? I thought it was Open Source.

-Wil

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文