OMXFocus.cpp revision d55379a7e975f992db1d10bba425f456447d14a8
1/* 2 * Copyright (C) Texas Instruments - http://www.ti.com/ 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17 18/** 19* @file OMXFocus.cpp 20* 21* This file contains functionality for handling focus configurations. 22* 23*/ 24 25#undef LOG_TAG 26 27#define LOG_TAG "CameraHAL" 28 29#include "CameraHal.h" 30#include "OMXCameraAdapter.h" 31#include "ErrorUtils.h" 32 33#define TOUCH_FOCUS_RANGE 0xFF 34#define AF_CALLBACK_TIMEOUT 10000000 //10 seconds timeout 35 36namespace android { 37 38status_t OMXCameraAdapter::setParametersFocus(const CameraParameters ¶ms, 39 BaseCameraAdapter::AdapterState state) 40{ 41 status_t ret = NO_ERROR; 42 const char *str = NULL; 43 Mutex::Autolock lock(mFocusAreasLock); 44 45 LOG_FUNCTION_NAME; 46 47 str = params.get(CameraParameters::KEY_FOCUS_AREAS); 48 mFocusAreas.clear(); 49 if ( NULL != str ) { 50 ret = CameraArea::parseFocusArea(str, strlen(str), mFocusAreas); 51 } 52 53 if ( NO_ERROR == ret ) { 54 if ( MAX_FOCUS_AREAS < mFocusAreas.size() ) { 55 CAMHAL_LOGEB("Focus areas supported %d, focus areas set %d", 56 MAX_FOCUS_AREAS, 57 mFocusAreas.size()); 58 ret = -EINVAL; 59 } 60 } 61 62 LOG_FUNCTION_NAME; 63 64 return ret; 65} 66 67status_t OMXCameraAdapter::doAutoFocus() 68{ 69 status_t ret = NO_ERROR; 70 OMX_ERRORTYPE eError = OMX_ErrorNone; 71 OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focusControl; 72 OMX_PARAM_FOCUSSTATUSTYPE focusStatus; 73 74 LOG_FUNCTION_NAME; 75 76 if ( OMX_StateExecuting != mComponentState ) 77 { 78 CAMHAL_LOGEA("OMX component not in executing state"); 79 returnFocusStatus(false); 80 return NO_INIT; 81 } 82 83 if ( 0 != mDoAFSem.Count() ) 84 { 85 CAMHAL_LOGEB("Error mDoAFSem semaphore count %d", mDoAFSem.Count()); 86 return NO_INIT; 87 } 88 89 // If the app calls autoFocus, the camera will stop sending face callbacks. 90 pauseFaceDetection(true); 91 92 OMX_INIT_STRUCT_PTR (&focusControl, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); 93 focusControl.eFocusControl = ( OMX_IMAGE_FOCUSCONTROLTYPE ) mParameters3A.Focus; 94 95 //In case we have CAF running we should first check the AF status. 96 //If it has managed to lock, then do as usual and return status 97 //immediately. If lock is not available, then switch temporarily 98 //to 'autolock' and do normal AF. 99 if ( mParameters3A.Focus == OMX_IMAGE_FocusControlAuto ) { 100//FIXME: The CAF seems to return focus failure all the time. 101// Probably this is tuning related, disable this until the 102// MMS IQ team fixes it 103#if 0 104 ret = checkFocus(&focusStatus); 105#else 106 ret = NO_ERROR; 107 focusStatus.eFocusStatus = OMX_FocusStatusReached; 108#endif 109 if ( NO_ERROR != ret ) { 110 CAMHAL_LOGEB("Focus status check failed 0x%x!", ret); 111 return ret; 112 } else { 113 CAMHAL_LOGDB("Focus status check 0x%x!", focusStatus.eFocusStatus); 114 } 115 116 if ( OMX_FocusStatusReached != focusStatus.eFocusStatus ) { 117 focusControl.eFocusControl = OMX_IMAGE_FocusControlAutoLock; 118 } 119 } 120 121 if ( ( focusControl.eFocusControl != OMX_IMAGE_FocusControlAuto ) && 122 ( focusControl.eFocusControl != ( OMX_IMAGE_FOCUSCONTROLTYPE ) 123 OMX_IMAGE_FocusControlAutoInfinity ) ) { 124 125 ret = RegisterForEvent(mCameraAdapterParameters.mHandleComp, 126 (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, 127 OMX_ALL, 128 OMX_IndexConfigCommonFocusStatus, 129 mDoAFSem); 130 131 if ( NO_ERROR == ret ) { 132 ret = setFocusCallback(true); 133 } 134 135 } 136 137 eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, 138 OMX_IndexConfigFocusControl, 139 &focusControl); 140 141 if ( OMX_ErrorNone != eError ) { 142 CAMHAL_LOGEB("Error while starting focus 0x%x", eError); 143 return INVALID_OPERATION; 144 } else { 145 CAMHAL_LOGDA("Autofocus started successfully"); 146 } 147 148 if ( ( focusControl.eFocusControl != OMX_IMAGE_FocusControlAuto ) && 149 ( focusControl.eFocusControl != ( OMX_IMAGE_FOCUSCONTROLTYPE ) 150 OMX_IMAGE_FocusControlAutoInfinity ) ) { 151 ret = mDoAFSem.WaitTimeout(AF_CALLBACK_TIMEOUT); 152 //Disable auto focus callback from Ducati 153 setFocusCallback(false); 154 //Signal a dummy AF event so that in case the callback from ducati 155 //does come then it doesnt crash after 156 //exiting this function since eventSem will go out of scope. 157 if(ret != NO_ERROR) { 158 CAMHAL_LOGEA("Autofocus callback timeout expired"); 159 SignalEvent(mCameraAdapterParameters.mHandleComp, 160 (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, 161 OMX_ALL, 162 OMX_IndexConfigCommonFocusStatus, 163 NULL ); 164 returnFocusStatus(true); 165 } else { 166 CAMHAL_LOGDA("Autofocus callback received"); 167 ret = returnFocusStatus(false); 168 } 169 170 } else { 171 if ( NO_ERROR == ret ) { 172 ret = returnFocusStatus(false); 173 } 174 } 175 176 //Restore CAF if needed 177 if ( ( mParameters3A.Focus == OMX_IMAGE_FocusControlAuto ) && 178 ( focusControl.eFocusControl == OMX_IMAGE_FocusControlAutoLock ) ) { 179 mPending3Asettings |= SetFocus; 180 } 181 182 LOG_FUNCTION_NAME_EXIT; 183 184 return ret; 185} 186 187status_t OMXCameraAdapter::stopAutoFocus() 188{ 189 status_t ret = NO_ERROR; 190 OMX_ERRORTYPE eError = OMX_ErrorNone; 191 OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focusControl; 192 193 LOG_FUNCTION_NAME; 194 195 if ( OMX_StateExecuting != mComponentState ) 196 { 197 CAMHAL_LOGEA("OMX component not in executing state"); 198 return NO_INIT; 199 } 200 201 if ( mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity ) { 202 // No need to stop focus if we are in infinity mode. Nothing to stop. 203 return NO_ERROR; 204 } 205 206 if ( NO_ERROR == ret ) 207 { 208 //Disable the callback first 209 ret = setFocusCallback(false); 210 } 211 212 if ( NO_ERROR == ret ) 213 { 214 OMX_INIT_STRUCT_PTR (&focusControl, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); 215 focusControl.eFocusControl = OMX_IMAGE_FocusControlOff; 216 217 eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, 218 OMX_IndexConfigFocusControl, 219 &focusControl); 220 if ( OMX_ErrorNone != eError ) 221 { 222 CAMHAL_LOGEB("Error while stopping focus 0x%x", eError); 223 return ErrorUtils::omxToAndroidError(eError); 224 } 225 } 226 227 //Query current focus distance after AF is complete 228 updateFocusDistances(mParameters); 229 230 LOG_FUNCTION_NAME_EXIT; 231 232 return ret; 233} 234 235status_t OMXCameraAdapter::getFocusMode(OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE &focusMode) 236{; 237 OMX_ERRORTYPE eError = OMX_ErrorNone; 238 239 LOG_FUNCTION_NAME; 240 241 if ( OMX_StateInvalid == mComponentState ) { 242 CAMHAL_LOGEA("OMX component is in invalid state"); 243 return NO_INIT; 244 } 245 246 OMX_INIT_STRUCT_PTR (&focusMode, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE); 247 focusMode.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; 248 249 eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, 250 OMX_IndexConfigFocusControl, 251 &focusMode); 252 253 if ( OMX_ErrorNone != eError ) { 254 CAMHAL_LOGEB("Error while retrieving focus mode 0x%x", eError); 255 } 256 257 LOG_FUNCTION_NAME_EXIT; 258 259 return ErrorUtils::omxToAndroidError(eError); 260} 261 262status_t OMXCameraAdapter::cancelAutoFocus() 263{ 264 status_t ret = NO_ERROR; 265 OMX_ERRORTYPE eError = OMX_ErrorNone; 266 OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE focusMode; 267 268 LOG_FUNCTION_NAME; 269 // Unlock 3A locks since they were locked by AF 270 if( set3ALock(OMX_FALSE) != NO_ERROR) { 271 CAMHAL_LOGEA("Error Unlocking 3A locks"); 272 } 273 else{ 274 CAMHAL_LOGDA("AE/AWB unlocked successfully"); 275 } 276 277 ret = getFocusMode(focusMode); 278 if ( NO_ERROR != ret ) { 279 return ret; 280 } 281 282 //Stop the AF only for modes other than CAF or Inifinity 283 if ( ( focusMode.eFocusControl != OMX_IMAGE_FocusControlAuto ) && 284 ( focusMode.eFocusControl != ( OMX_IMAGE_FOCUSCONTROLTYPE ) 285 OMX_IMAGE_FocusControlAutoInfinity ) ) { 286 stopAutoFocus(); 287 //Signal a dummy AF event so that in case the callback from ducati 288 //does come then it doesnt crash after 289 //exiting this function since eventSem will go out of scope. 290 ret |= SignalEvent(mCameraAdapterParameters.mHandleComp, 291 (OMX_EVENTTYPE) OMX_EventIndexSettingChanged, 292 OMX_ALL, 293 OMX_IndexConfigCommonFocusStatus, 294 NULL ); 295 } 296 297 // If the apps call #cancelAutoFocus()}, the face callbacks will also resume. 298 pauseFaceDetection(false); 299 300 LOG_FUNCTION_NAME_EXIT; 301 302 return ret; 303 304} 305 306status_t OMXCameraAdapter::setFocusCallback(bool enabled) 307{ 308 status_t ret = NO_ERROR; 309 OMX_ERRORTYPE eError = OMX_ErrorNone; 310 OMX_CONFIG_CALLBACKREQUESTTYPE focusRequstCallback; 311 312 LOG_FUNCTION_NAME; 313 314 if ( OMX_StateExecuting != mComponentState ) 315 { 316 CAMHAL_LOGEA("OMX component not in executing state"); 317 ret = -1; 318 } 319 320 if ( NO_ERROR == ret ) 321 { 322 323 OMX_INIT_STRUCT_PTR (&focusRequstCallback, OMX_CONFIG_CALLBACKREQUESTTYPE); 324 focusRequstCallback.nPortIndex = OMX_ALL; 325 focusRequstCallback.nIndex = OMX_IndexConfigCommonFocusStatus; 326 327 if ( enabled ) 328 { 329 focusRequstCallback.bEnable = OMX_TRUE; 330 } 331 else 332 { 333 focusRequstCallback.bEnable = OMX_FALSE; 334 } 335 336 eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, 337 (OMX_INDEXTYPE) OMX_IndexConfigCallbackRequest, 338 &focusRequstCallback); 339 if ( OMX_ErrorNone != eError ) 340 { 341 CAMHAL_LOGEB("Error registering focus callback 0x%x", eError); 342 ret = -1; 343 } 344 else 345 { 346 CAMHAL_LOGDB("Autofocus callback for index 0x%x registered successfully", 347 OMX_IndexConfigCommonFocusStatus); 348 } 349 } 350 351 LOG_FUNCTION_NAME_EXIT; 352 353 return ret; 354} 355 356status_t OMXCameraAdapter::returnFocusStatus(bool timeoutReached) 357{ 358 status_t ret = NO_ERROR; 359 OMX_PARAM_FOCUSSTATUSTYPE eFocusStatus; 360 bool focusStatus = false; 361 BaseCameraAdapter::AdapterState state; 362 BaseCameraAdapter::getState(state); 363 364 LOG_FUNCTION_NAME; 365 366 OMX_INIT_STRUCT(eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE); 367 368 if( ( AF_ACTIVE & state ) != AF_ACTIVE ) 369 { 370 /// We don't send focus callback if focus was not started 371 return NO_ERROR; 372 } 373 374 if ( NO_ERROR == ret ) 375 { 376 377 if ( !timeoutReached ) 378 { 379 ret = checkFocus(&eFocusStatus); 380 381 if ( NO_ERROR != ret ) 382 { 383 CAMHAL_LOGEA("Focus status check failed!"); 384 } 385 } 386 } 387 388 if ( NO_ERROR == ret ) 389 { 390 391 if ( timeoutReached ) 392 { 393 focusStatus = false; 394 } 395 ///FIXME: The ducati seems to return focus as false always if continuous focus is enabled 396 ///So, return focus as locked always until this is fixed. 397 else if(mParameters3A.Focus == OMX_IMAGE_FocusControlAuto ) 398 { 399 focusStatus = true; 400 } 401 else 402 { 403 switch (eFocusStatus.eFocusStatus) 404 { 405 case OMX_FocusStatusReached: 406 { 407 focusStatus = true; 408 //Lock the AE and AWB here sinc the focus is locked 409 // Apply 3A locks after AF 410 if( set3ALock(OMX_TRUE) != NO_ERROR) { 411 CAMHAL_LOGEA("Error Applying 3A locks"); 412 } 413 else 414 { 415 CAMHAL_LOGDA("Focus locked. Applied focus locks successfully"); 416 } 417 break; 418 } 419 case OMX_FocusStatusOff: 420 case OMX_FocusStatusUnableToReach: 421 case OMX_FocusStatusRequest: 422 default: 423 { 424 focusStatus = false; 425 break; 426 } 427 } 428 429 stopAutoFocus(); 430 } 431 } 432 433 ret = BaseCameraAdapter::setState(CAMERA_CANCEL_AUTOFOCUS); 434 if ( NO_ERROR == ret ) 435 { 436 ret = BaseCameraAdapter::commitState(); 437 } 438 else 439 { 440 ret |= BaseCameraAdapter::rollbackState(); 441 } 442 443 if ( NO_ERROR == ret ) 444 { 445 notifyFocusSubscribers(focusStatus); 446 } 447 448 // After focus, face detection will resume sending face callbacks 449 pauseFaceDetection(false); 450 451 LOG_FUNCTION_NAME_EXIT; 452 453 return ret; 454} 455 456status_t OMXCameraAdapter::checkFocus(OMX_PARAM_FOCUSSTATUSTYPE *eFocusStatus) 457{ 458 status_t ret = NO_ERROR; 459 OMX_ERRORTYPE eError = OMX_ErrorNone; 460 461 LOG_FUNCTION_NAME; 462 463 if ( NULL == eFocusStatus ) 464 { 465 CAMHAL_LOGEA("Invalid focus status"); 466 ret = -EINVAL; 467 } 468 469 if ( OMX_StateExecuting != mComponentState ) 470 { 471 CAMHAL_LOGEA("OMX component not in executing state"); 472 ret = -EINVAL; 473 } 474 475 if ( NO_ERROR == ret ) 476 { 477 OMX_INIT_STRUCT_PTR (eFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE); 478 479 eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, 480 OMX_IndexConfigCommonFocusStatus, 481 eFocusStatus); 482 if ( OMX_ErrorNone != eError ) 483 { 484 CAMHAL_LOGEB("Error while retrieving focus status: 0x%x", eError); 485 ret = -1; 486 } 487 } 488 489 if ( NO_ERROR == ret ) 490 { 491 CAMHAL_LOGDB("Focus Status: %d", eFocusStatus->eFocusStatus); 492 } 493 494 LOG_FUNCTION_NAME_EXIT; 495 496 return ret; 497} 498 499status_t OMXCameraAdapter::updateFocusDistances(CameraParameters ¶ms) 500{ 501 OMX_U32 focusNear, focusOptimal, focusFar; 502 status_t ret = NO_ERROR; 503 504 LOG_FUNCTION_NAME; 505 506 ret = getFocusDistances(focusNear, focusOptimal, focusFar); 507 if ( NO_ERROR == ret) 508 { 509 ret = addFocusDistances(focusNear, focusOptimal, focusFar, params); 510 if ( NO_ERROR != ret ) 511 { 512 CAMHAL_LOGEB("Error in call to addFocusDistances() 0x%x", ret); 513 } 514 } 515 else 516 { 517 CAMHAL_LOGEB("Error in call to getFocusDistances() 0x%x", ret); 518 } 519 520 LOG_FUNCTION_NAME_EXIT; 521 522 return ret; 523} 524 525status_t OMXCameraAdapter::getFocusDistances(OMX_U32 &near,OMX_U32 &optimal, OMX_U32 &far) 526{ 527 status_t ret = NO_ERROR; 528 OMX_ERRORTYPE eError; 529 530 OMX_TI_CONFIG_FOCUSDISTANCETYPE focusDist; 531 532 LOG_FUNCTION_NAME; 533 534 if ( OMX_StateInvalid == mComponentState ) 535 { 536 CAMHAL_LOGEA("OMX component is in invalid state"); 537 ret = UNKNOWN_ERROR; 538 } 539 540 if ( NO_ERROR == ret ) 541 { 542 OMX_INIT_STRUCT_PTR(&focusDist, OMX_TI_CONFIG_FOCUSDISTANCETYPE); 543 focusDist.nPortIndex = mCameraAdapterParameters.mPrevPortIndex; 544 545 eError = OMX_GetConfig(mCameraAdapterParameters.mHandleComp, 546 ( OMX_INDEXTYPE ) OMX_TI_IndexConfigFocusDistance, 547 &focusDist); 548 if ( OMX_ErrorNone != eError ) 549 { 550 CAMHAL_LOGEB("Error while querying focus distances 0x%x", eError); 551 ret = UNKNOWN_ERROR; 552 } 553 554 } 555 556 if ( NO_ERROR == ret ) 557 { 558 near = focusDist.nFocusDistanceNear; 559 optimal = focusDist.nFocusDistanceOptimal; 560 far = focusDist.nFocusDistanceFar; 561 } 562 563 LOG_FUNCTION_NAME_EXIT; 564 565 return ret; 566} 567 568status_t OMXCameraAdapter::encodeFocusDistance(OMX_U32 dist, char *buffer, size_t length) 569{ 570 status_t ret = NO_ERROR; 571 uint32_t focusScale = 1000; 572 float distFinal; 573 574 LOG_FUNCTION_NAME; 575 576 if(mParameters3A.Focus == OMX_IMAGE_FocusControlAutoInfinity) 577 { 578 dist=0; 579 } 580 581 if ( NO_ERROR == ret ) 582 { 583 if ( 0 == dist ) 584 { 585 strncpy(buffer, CameraParameters::FOCUS_DISTANCE_INFINITY, ( length - 1 )); 586 } 587 else 588 { 589 distFinal = dist; 590 distFinal /= focusScale; 591 snprintf(buffer, ( length - 1 ) , "%5.3f", distFinal); 592 } 593 } 594 595 LOG_FUNCTION_NAME_EXIT; 596 597 return ret; 598} 599 600status_t OMXCameraAdapter::addFocusDistances(OMX_U32 &near, 601 OMX_U32 &optimal, 602 OMX_U32 &far, 603 CameraParameters& params) 604{ 605 status_t ret = NO_ERROR; 606 607 LOG_FUNCTION_NAME; 608 609 if ( NO_ERROR == ret ) 610 { 611 ret = encodeFocusDistance(near, mFocusDistNear, FOCUS_DIST_SIZE); 612 if ( NO_ERROR != ret ) 613 { 614 CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); 615 } 616 } 617 618 if ( NO_ERROR == ret ) 619 { 620 ret = encodeFocusDistance(optimal, mFocusDistOptimal, FOCUS_DIST_SIZE); 621 if ( NO_ERROR != ret ) 622 { 623 CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); 624 } 625 } 626 627 if ( NO_ERROR == ret ) 628 { 629 ret = encodeFocusDistance(far, mFocusDistFar, FOCUS_DIST_SIZE); 630 if ( NO_ERROR != ret ) 631 { 632 CAMHAL_LOGEB("Error encoding near focus distance 0x%x", ret); 633 } 634 } 635 636 if ( NO_ERROR == ret ) 637 { 638 snprintf(mFocusDistBuffer, ( FOCUS_DIST_BUFFER_SIZE - 1) ,"%s,%s,%s", mFocusDistNear, 639 mFocusDistOptimal, 640 mFocusDistFar); 641 642 params.set(CameraParameters::KEY_FOCUS_DISTANCES, mFocusDistBuffer); 643 } 644 645 LOG_FUNCTION_NAME_EXIT; 646 647 return ret; 648} 649 650status_t OMXCameraAdapter::setTouchFocus(size_t posX, 651 size_t posY, 652 size_t posWidth, 653 size_t posHeight, 654 size_t previewWidth, 655 size_t previewHeight) 656{ 657 status_t ret = NO_ERROR; 658 OMX_ERRORTYPE eError = OMX_ErrorNone; 659 OMX_CONFIG_EXTFOCUSREGIONTYPE touchControl; 660 661 LOG_FUNCTION_NAME; 662 663 if ( OMX_StateInvalid == mComponentState ) 664 { 665 CAMHAL_LOGEA("OMX component is in invalid state"); 666 ret = -1; 667 } 668 669 if ( NO_ERROR == ret ) 670 { 671 OMX_INIT_STRUCT_PTR (&touchControl, OMX_CONFIG_EXTFOCUSREGIONTYPE); 672 touchControl.nLeft = ( posX * TOUCH_FOCUS_RANGE ) / previewWidth; 673 touchControl.nTop = ( posY * TOUCH_FOCUS_RANGE ) / previewHeight; 674 touchControl.nWidth = ( posWidth * TOUCH_FOCUS_RANGE ) / previewWidth; 675 touchControl.nHeight = ( posHeight * TOUCH_FOCUS_RANGE ) / previewHeight; 676 677 eError = OMX_SetConfig(mCameraAdapterParameters.mHandleComp, 678 ( OMX_INDEXTYPE ) OMX_IndexConfigExtFocusRegion, 679 &touchControl); 680 if ( OMX_ErrorNone != eError ) 681 { 682 CAMHAL_LOGEB("Error while configuring touch focus 0x%x", eError); 683 ret = -1; 684 } 685 else 686 { 687 CAMHAL_LOGDB("Touch focus %d,%d %d,%d configured successfuly", 688 ( int ) touchControl.nLeft, 689 ( int ) touchControl.nTop, 690 ( int ) touchControl.nWidth, 691 ( int ) touchControl.nHeight); 692 } 693 } 694 695 LOG_FUNCTION_NAME_EXIT; 696 697 return ret; 698} 699 700}; 701